diff --git a/logging/BUILD.gn b/logging/BUILD.gn index 8f81e7a7c9..a47c81d370 100644 --- a/logging/BUILD.gn +++ b/logging/BUILD.gn @@ -253,8 +253,8 @@ if (rtc_enable_protobuf) { rtc_static_library("rtc_event_log_parser") { sources = [ - "rtc_event_log/rtc_event_log_parser2.cc", - "rtc_event_log/rtc_event_log_parser2.h", + "rtc_event_log/rtc_event_log_parser.cc", + "rtc_event_log/rtc_event_log_parser.h", ] deps = [ @@ -265,7 +265,6 @@ if (rtc_enable_protobuf) { ":rtc_event_log_proto", ":rtc_stream_config", "..:webrtc_common", - "../api:libjingle_peerconnection_api", "../call:video_stream_api", "../modules/audio_coding:audio_network_adaptor", "../modules/remote_bitrate_estimator:remote_bitrate_estimator", @@ -366,7 +365,6 @@ if (rtc_enable_protobuf) { "../rtc_base:checks", "../rtc_base:protobuf_utils", "../rtc_base:rtc_base_approved", - "../rtc_base:stringutils", # TODO(kwiberg): Remove this dependency. "../api/audio_codecs:audio_codecs_api", diff --git a/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc b/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc index 0e6e183e0f..6d882987d4 100644 --- a/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc +++ b/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc @@ -32,7 +32,7 @@ #include "logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h" #include "logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h" #include "logging/rtc_event_log/events/rtc_event_video_send_stream_config.h" -#include "logging/rtc_event_log/rtc_event_log_parser2.h" +#include "logging/rtc_event_log/rtc_event_log_parser.h" #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h" #include "modules/remote_bitrate_estimator/include/bwe_defines.h" #include "modules/rtp_rtcp/source/rtcp_packet/bye.h" // Arbitrary RTCP message. @@ -142,11 +142,11 @@ void RtcEventLogEncoderTest::TestRtcEventAudioNetworkAdaptation( ASSERT_EQ(parsed_log_.GetEventType(0), ParsedRtcEventLog::AUDIO_NETWORK_ADAPTATION_EVENT); - LoggedAudioNetworkAdaptationEvent parsed_event = - parsed_log_.GetAudioNetworkAdaptation(0); + AudioEncoderRuntimeConfig parsed_runtime_config; + parsed_log_.GetAudioNetworkAdaptation(0, &parsed_runtime_config); - EXPECT_EQ(parsed_event.timestamp_us, timestamp_us); - EXPECT_EQ(parsed_event.config, original_runtime_config); + EXPECT_EQ(parsed_log_.GetTimestamp(0), timestamp_us); + EXPECT_EQ(parsed_runtime_config, original_runtime_config); } TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationBitrate) { @@ -234,10 +234,11 @@ TEST_P(RtcEventLogEncoderTest, RtcEventAudioPlayout) { ASSERT_EQ(parsed_log_.GetEventType(0), ParsedRtcEventLog::AUDIO_PLAYOUT_EVENT); - LoggedAudioPlayoutEvent playout_event = parsed_log_.GetAudioPlayout(0); + uint32_t parsed_ssrc; + parsed_log_.GetAudioPlayout(0, &parsed_ssrc); - EXPECT_EQ(playout_event.timestamp_us, timestamp_us); - EXPECT_EQ(playout_event.ssrc, ssrc); + EXPECT_EQ(parsed_log_.GetTimestamp(0), timestamp_us); + EXPECT_EQ(parsed_ssrc, ssrc); } TEST_P(RtcEventLogEncoderTest, RtcEventAudioReceiveStreamConfig) { @@ -332,12 +333,16 @@ TEST_P(RtcEventLogEncoderTest, RtcEventBweUpdateLossBased) { ASSERT_EQ(parsed_log_.GetEventType(0), ParsedRtcEventLog::LOSS_BASED_BWE_UPDATE); - LoggedBweLossBasedUpdate bwe_update = parsed_log_.GetLossBasedBweUpdate(0); + int32_t parsed_bitrate_bps; + uint8_t parsed_fraction_loss; + int32_t parsed_total_packets; + parsed_log_.GetLossBasedBweUpdate( + 0, &parsed_bitrate_bps, &parsed_fraction_loss, &parsed_total_packets); - EXPECT_EQ(bwe_update.timestamp_us, timestamp_us); - EXPECT_EQ(bwe_update.bitrate_bps, bitrate_bps); - EXPECT_EQ(bwe_update.fraction_lost, fraction_loss); - EXPECT_EQ(bwe_update.expected_packets, total_packets); + EXPECT_EQ(parsed_log_.GetTimestamp(0), timestamp_us); + EXPECT_EQ(parsed_bitrate_bps, bitrate_bps); + EXPECT_EQ(parsed_fraction_loss, fraction_loss); + EXPECT_EQ(parsed_total_packets, total_packets); } TEST_P(RtcEventLogEncoderTest, RtcEventLoggingStarted) { diff --git a/logging/rtc_event_log/rtc_event_log.h b/logging/rtc_event_log/rtc_event_log.h index 0c71406902..a0714e0bdb 100644 --- a/logging/rtc_event_log/rtc_event_log.h +++ b/logging/rtc_event_log/rtc_event_log.h @@ -21,7 +21,6 @@ namespace webrtc { -// TODO(terelius): Move this to the parser. enum PacketDirection { kIncomingPacket = 0, kOutgoingPacket }; class RtcEventLog { diff --git a/logging/rtc_event_log/rtc_event_log2rtp_dump.cc b/logging/rtc_event_log/rtc_event_log2rtp_dump.cc index c4d6948227..c6fa12997b 100644 --- a/logging/rtc_event_log/rtc_event_log2rtp_dump.cc +++ b/logging/rtc_event_log/rtc_event_log2rtp_dump.cc @@ -16,7 +16,7 @@ #include #include "logging/rtc_event_log/rtc_event_log.h" -#include "logging/rtc_event_log/rtc_event_log_parser2.h" +#include "logging/rtc_event_log/rtc_event_log_parser.h" #include "modules/rtp_rtcp/source/byte_io.h" #include "modules/rtp_rtcp/source/rtp_utility.h" #include "rtc_base/checks.h" diff --git a/logging/rtc_event_log/rtc_event_log2text.cc b/logging/rtc_event_log/rtc_event_log2text.cc index 6ceeaaf879..c71a2b8023 100644 --- a/logging/rtc_event_log/rtc_event_log2text.cc +++ b/logging/rtc_event_log/rtc_event_log2text.cc @@ -13,12 +13,13 @@ #include // setfill, setw #include #include +#include #include #include // pair #include "call/video_config.h" #include "common_types.h" // NOLINT(build/include) -#include "logging/rtc_event_log/rtc_event_log_parser2.h" +#include "logging/rtc_event_log/rtc_event_log_parser.h" #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h" #include "modules/rtp_rtcp/source/rtcp_packet/bye.h" #include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" @@ -39,7 +40,6 @@ #include "rtc_base/checks.h" #include "rtc_base/flags.h" #include "rtc_base/logging.h" -#include "rtc_base/strings/string_builder.h" namespace { @@ -443,7 +443,7 @@ int main(int argc, char* argv[]) { size_t total_length; uint8_t header[IP_PACKET_SIZE]; webrtc::PacketDirection direction; - const webrtc::RtpHeaderExtensionMap* extension_map = + webrtc::RtpHeaderExtensionMap* extension_map = parsed_stream.GetRtpHeader(i, &direction, header, &header_length, &total_length, nullptr); @@ -583,9 +583,10 @@ int main(int argc, char* argv[]) { case webrtc::ParsedRtcEventLog::AUDIO_PLAYOUT_EVENT: { if (FLAG_playout) { - auto audio_playout = parsed_stream.GetAudioPlayout(i); - std::cout << audio_playout.log_time_us() << "\tAUDIO_PLAYOUT" - << "\tssrc=" << audio_playout.ssrc << std::endl; + uint32_t ssrc; + parsed_stream.GetAudioPlayout(i, &ssrc); + std::cout << parsed_stream.GetTimestamp(i) << "\tAUDIO_PLAYOUT" + << "\tssrc=" << ssrc << std::endl; } event_recognized = true; break; @@ -593,13 +594,15 @@ int main(int argc, char* argv[]) { case webrtc::ParsedRtcEventLog::LOSS_BASED_BWE_UPDATE: { if (FLAG_bwe) { - auto bwe_update = parsed_stream.GetLossBasedBweUpdate(i); - std::cout << bwe_update.log_time_us() << "\tBWE(LOSS_BASED)" - << "\tbitrate_bps=" << bwe_update.bitrate_bps - << "\tfraction_lost=" - << static_cast(bwe_update.fraction_lost) - << "\texpected_packets=" << bwe_update.expected_packets - << std::endl; + int32_t bitrate_bps; + uint8_t fraction_loss; + int32_t total_packets; + parsed_stream.GetLossBasedBweUpdate(i, &bitrate_bps, &fraction_loss, + &total_packets); + std::cout << parsed_stream.GetTimestamp(i) << "\tBWE(LOSS_BASED)" + << "\tbitrate_bps=" << bitrate_bps << "\tfraction_loss=" + << static_cast(fraction_loss) + << "\ttotal_packets=" << total_packets << std::endl; } event_recognized = true; break; @@ -608,7 +611,7 @@ int main(int argc, char* argv[]) { case webrtc::ParsedRtcEventLog::DELAY_BASED_BWE_UPDATE: { if (FLAG_bwe) { auto bwe_update = parsed_stream.GetDelayBasedBweUpdate(i); - std::cout << bwe_update.log_time_us() << "\tBWE(DELAY_BASED)" + std::cout << parsed_stream.GetTimestamp(i) << "\tBWE(DELAY_BASED)" << "\tbitrate_bps=" << bwe_update.bitrate_bps << "\tdetector_state=" << static_cast(bwe_update.detector_state) << std::endl; @@ -720,31 +723,30 @@ int main(int argc, char* argv[]) { case webrtc::ParsedRtcEventLog::AUDIO_NETWORK_ADAPTATION_EVENT: { if (FLAG_ana) { - auto ana_event = parsed_stream.GetAudioNetworkAdaptation(i); - char buffer[300]; - rtc::SimpleStringBuilder builder(buffer); - builder << parsed_stream.GetTimestamp(i) << "\tANA_UPDATE"; - if (ana_event.config.bitrate_bps) { - builder << "\tbitrate_bps=" << *ana_event.config.bitrate_bps; + webrtc::AudioEncoderRuntimeConfig ana_config; + parsed_stream.GetAudioNetworkAdaptation(i, &ana_config); + std::stringstream ss; + ss << parsed_stream.GetTimestamp(i) << "\tANA_UPDATE"; + if (ana_config.bitrate_bps) { + ss << "\tbitrate_bps=" << *ana_config.bitrate_bps; } - if (ana_event.config.frame_length_ms) { - builder << "\tframe_length_ms=" - << *ana_event.config.frame_length_ms; + if (ana_config.frame_length_ms) { + ss << "\tframe_length_ms=" << *ana_config.frame_length_ms; } - if (ana_event.config.uplink_packet_loss_fraction) { - builder << "\tuplink_packet_loss_fraction=" - << *ana_event.config.uplink_packet_loss_fraction; + if (ana_config.uplink_packet_loss_fraction) { + ss << "\tuplink_packet_loss_fraction=" + << *ana_config.uplink_packet_loss_fraction; } - if (ana_event.config.enable_fec) { - builder << "\tenable_fec=" << *ana_event.config.enable_fec; + if (ana_config.enable_fec) { + ss << "\tenable_fec=" << *ana_config.enable_fec; } - if (ana_event.config.enable_dtx) { - builder << "\tenable_dtx=" << *ana_event.config.enable_dtx; + if (ana_config.enable_dtx) { + ss << "\tenable_dtx=" << *ana_config.enable_dtx; } - if (ana_event.config.num_channels) { - builder << "\tnum_channels=" << *ana_event.config.num_channels; + if (ana_config.num_channels) { + ss << "\tnum_channels=" << *ana_config.num_channels; } - std::cout << builder.str() << std::endl; + std::cout << ss.str() << std::endl; } event_recognized = true; break; @@ -752,7 +754,8 @@ int main(int argc, char* argv[]) { case webrtc::ParsedRtcEventLog::BWE_PROBE_CLUSTER_CREATED_EVENT: { if (FLAG_probe) { - auto probe_event = parsed_stream.GetBweProbeClusterCreated(i); + webrtc::ParsedRtcEventLog::BweProbeClusterCreatedEvent probe_event = + parsed_stream.GetBweProbeClusterCreated(i); std::cout << parsed_stream.GetTimestamp(i) << "\tPROBE_CREATED(" << probe_event.id << ")" << "\tbitrate_bps=" << probe_event.bitrate_bps @@ -765,7 +768,7 @@ int main(int argc, char* argv[]) { case webrtc::ParsedRtcEventLog::BWE_PROBE_RESULT_EVENT: { if (FLAG_probe) { - webrtc::LoggedBweProbeResultEvent probe_result = + webrtc::ParsedRtcEventLog::BweProbeResultEvent probe_result = parsed_stream.GetBweProbeResult(i); if (probe_result.failure_reason) { std::cout << parsed_stream.GetTimestamp(i) << "\tPROBE_SUCCESS(" @@ -786,7 +789,8 @@ int main(int argc, char* argv[]) { case webrtc::ParsedRtcEventLog::ALR_STATE_EVENT: { if (FLAG_bwe) { - webrtc::LoggedAlrStateEvent alr_state = parsed_stream.GetAlrState(i); + webrtc::ParsedRtcEventLog::AlrStateEvent alr_state = + parsed_stream.GetAlrState(i); std::cout << parsed_stream.GetTimestamp(i) << "\tALR_STATE" << "\tin_alr=" << alr_state.in_alr << std::endl; } @@ -796,7 +800,7 @@ int main(int argc, char* argv[]) { case webrtc::ParsedRtcEventLog::ICE_CANDIDATE_PAIR_CONFIG: { if (FLAG_ice) { - webrtc::LoggedIceCandidatePairConfig ice_cp_config = + 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) @@ -810,7 +814,7 @@ int main(int argc, char* argv[]) { case webrtc::ParsedRtcEventLog::ICE_CANDIDATE_PAIR_EVENT: { if (FLAG_ice) { - webrtc::LoggedIceCandidatePairEvent ice_cp_event = + 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) diff --git a/logging/rtc_event_log/rtc_event_log_parser2.cc b/logging/rtc_event_log/rtc_event_log_parser2.cc deleted file mode 100644 index 9bcad0dd32..0000000000 --- a/logging/rtc_event_log/rtc_event_log_parser2.cc +++ /dev/null @@ -1,1248 +0,0 @@ -/* - * 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_parser2.h" - -#include -#include - -#include -#include -#include // no-presubmit-check TODO(webrtc:8982) -#include -#include -#include - -#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; -} - -ParsedRtcEventLog::EventType GetRuntimeEventType( - rtclog::Event::EventType event_type) { - switch (event_type) { - case rtclog::Event::UNKNOWN_EVENT: - return ParsedRtcEventLog::EventType::UNKNOWN_EVENT; - case rtclog::Event::LOG_START: - return ParsedRtcEventLog::EventType::LOG_START; - case rtclog::Event::LOG_END: - return ParsedRtcEventLog::EventType::LOG_END; - case rtclog::Event::RTP_EVENT: - return ParsedRtcEventLog::EventType::RTP_EVENT; - case rtclog::Event::RTCP_EVENT: - return ParsedRtcEventLog::EventType::RTCP_EVENT; - case rtclog::Event::AUDIO_PLAYOUT_EVENT: - return ParsedRtcEventLog::EventType::AUDIO_PLAYOUT_EVENT; - case rtclog::Event::LOSS_BASED_BWE_UPDATE: - return ParsedRtcEventLog::EventType::LOSS_BASED_BWE_UPDATE; - case rtclog::Event::DELAY_BASED_BWE_UPDATE: - return ParsedRtcEventLog::EventType::DELAY_BASED_BWE_UPDATE; - case rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT: - return ParsedRtcEventLog::EventType::VIDEO_RECEIVER_CONFIG_EVENT; - case rtclog::Event::VIDEO_SENDER_CONFIG_EVENT: - return ParsedRtcEventLog::EventType::VIDEO_SENDER_CONFIG_EVENT; - case rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT: - return ParsedRtcEventLog::EventType::AUDIO_RECEIVER_CONFIG_EVENT; - case rtclog::Event::AUDIO_SENDER_CONFIG_EVENT: - return ParsedRtcEventLog::EventType::AUDIO_SENDER_CONFIG_EVENT; - case rtclog::Event::AUDIO_NETWORK_ADAPTATION_EVENT: - return ParsedRtcEventLog::EventType::AUDIO_NETWORK_ADAPTATION_EVENT; - case rtclog::Event::BWE_PROBE_CLUSTER_CREATED_EVENT: - return ParsedRtcEventLog::EventType::BWE_PROBE_CLUSTER_CREATED_EVENT; - case rtclog::Event::BWE_PROBE_RESULT_EVENT: - 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; -} - -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; -} - -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; -} - -// 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(webrtc::RtpExtension::kAudioLevelDefaultId); - default_map.Register( - webrtc::RtpExtension::kTimestampOffsetDefaultId); - default_map.Register( - webrtc::RtpExtension::kAbsSendTimeDefaultId); - default_map.Register( - webrtc::RtpExtension::kVideoRotationDefaultId); - default_map.Register( - webrtc::RtpExtension::kVideoContentTypeDefaultId); - default_map.Register( - webrtc::RtpExtension::kVideoTimingDefaultId); - default_map.Register( - webrtc::RtpExtension::kTransportSequenceNumberDefaultId); - default_map.Register( - webrtc::RtpExtension::kPlayoutDelayDefaultId); - return default_map; -} - -std::pair 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(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* header_extensions, - const RepeatedPtrField& - 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 - -ParsedRtcEventLog::ParsedRtcEventLog( - UnconfiguredHeaderExtensions parse_unconfigured_header_extensions) - : parse_unconfigured_header_extensions_( - parse_unconfigured_header_extensions) { - Clear(); -} - -void ParsedRtcEventLog::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_result_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::max(); - last_timestamp_ = std::numeric_limits::min(); - - incoming_rtp_extensions_maps_.clear(); - outgoing_rtp_extensions_maps_.clear(); -} - -bool ParsedRtcEventLog::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 ParsedRtcEventLog::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 ParsedRtcEventLog::ParseStream( - std::istream& stream) { // no-presubmit-check TODO(webrtc:8982) - Clear(); - const size_t kMaxEventSize = (1u << 16) - 1; - std::vector 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(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); - } - - // Move 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); - } - 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); - } - - // 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 true; -} - -void ParsedRtcEventLog::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 (event.type()) { - case rtclog::Event::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 rtclog::Event::VIDEO_SENDER_CONFIG_EVENT: { - std::vector 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 rtclog::Event::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 rtclog::Event::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 rtclog::Event::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 rtclog::Event::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 ParsedRtcEventLog::LOG_START: { - start_log_events_.push_back(LoggedStartEvent(GetTimestamp(event))); - break; - } - case ParsedRtcEventLog::LOG_END: { - stop_log_events_.push_back(LoggedStopEvent(GetTimestamp(event))); - break; - } - case ParsedRtcEventLog::AUDIO_PLAYOUT_EVENT: { - LoggedAudioPlayoutEvent playout_event = GetAudioPlayout(event); - audio_playout_events_[playout_event.ssrc].push_back( - playout_event.timestamp_us); - break; - } - case ParsedRtcEventLog::LOSS_BASED_BWE_UPDATE: { - bwe_loss_updates_.push_back(GetLossBasedBweUpdate(event)); - break; - } - case ParsedRtcEventLog::DELAY_BASED_BWE_UPDATE: { - bwe_delay_updates_.push_back(GetDelayBasedBweUpdate(event)); - break; - } - case ParsedRtcEventLog::AUDIO_NETWORK_ADAPTATION_EVENT: { - LoggedAudioNetworkAdaptationEvent ana_event = - GetAudioNetworkAdaptation(event); - audio_network_adaptation_events_.push_back(ana_event); - break; - } - case ParsedRtcEventLog::BWE_PROBE_CLUSTER_CREATED_EVENT: { - bwe_probe_cluster_created_events_.push_back( - GetBweProbeClusterCreated(event)); - break; - } - case ParsedRtcEventLog::BWE_PROBE_RESULT_EVENT: { - bwe_probe_result_events_.push_back(GetBweProbeResult(event)); - break; - } - case ParsedRtcEventLog::ALR_STATE_EVENT: { - alr_state_events_.push_back(GetAlrState(event)); - break; - } - case ParsedRtcEventLog::ICE_CANDIDATE_PAIR_CONFIG: { - ice_candidate_pair_configs_.push_back(GetIceCandidatePairConfig(event)); - break; - } - case ParsedRtcEventLog::ICE_CANDIDATE_PAIR_EVENT: { - ice_candidate_pair_events_.push_back(GetIceCandidatePairEvent(event)); - break; - } - case ParsedRtcEventLog::UNKNOWN_EVENT: { - break; - } - } -} - -size_t ParsedRtcEventLog::GetNumberOfEvents() const { - return events_.size(); -} - -int64_t ParsedRtcEventLog::GetTimestamp(size_t index) const { - RTC_CHECK_LT(index, GetNumberOfEvents()); - const rtclog::Event& event = events_[index]; - return GetTimestamp(event); -} - -int64_t ParsedRtcEventLog::GetTimestamp(const rtclog::Event& event) const { - RTC_CHECK(event.has_timestamp_us()); - return event.timestamp_us(); -} - -ParsedRtcEventLog::EventType ParsedRtcEventLog::GetEventType( - size_t index) const { - RTC_CHECK_LT(index, GetNumberOfEvents()); - const rtclog::Event& event = events_[index]; - RTC_CHECK(event.has_type()); - return GetRuntimeEventType(event.type()); -} - -// The header must have space for at least IP_PACKET_SIZE bytes. -const webrtc::RtpHeaderExtensionMap* ParsedRtcEventLog::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* ParsedRtcEventLog::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(IP_PACKET_SIZE)); - memcpy(header, rtp_packet.header().data(), rtp_packet.header().size()); - uint32_t ssrc = ByteReader::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 ParsedRtcEventLog::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 ParsedRtcEventLog::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(IP_PACKET_SIZE)); - memcpy(packet, rtcp_packet.packet_data().data(), - rtcp_packet.packet_data().size()); - } -} - -rtclog::StreamConfig ParsedRtcEventLog::GetVideoReceiveConfig( - size_t index) const { - RTC_CHECK_LT(index, GetNumberOfEvents()); - return GetVideoReceiveConfig(events_[index]); -} - -rtclog::StreamConfig ParsedRtcEventLog::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 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 ParsedRtcEventLog::GetVideoSendConfig( - size_t index) const { - RTC_CHECK_LT(index, GetNumberOfEvents()); - return GetVideoSendConfig(events_[index]); -} - -std::vector ParsedRtcEventLog::GetVideoSendConfig( - const rtclog::Event& event) const { - std::vector 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 ParsedRtcEventLog::GetAudioReceiveConfig( - size_t index) const { - RTC_CHECK_LT(index, GetNumberOfEvents()); - return GetAudioReceiveConfig(events_[index]); -} - -rtclog::StreamConfig ParsedRtcEventLog::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 ParsedRtcEventLog::GetAudioSendConfig(size_t index) const { - RTC_CHECK_LT(index, GetNumberOfEvents()); - return GetAudioSendConfig(events_[index]); -} - -rtclog::StreamConfig ParsedRtcEventLog::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 ParsedRtcEventLog::GetAudioPlayout(size_t index) const { - RTC_CHECK_LT(index, GetNumberOfEvents()); - const rtclog::Event& event = events_[index]; - return GetAudioPlayout(event); -} - -LoggedAudioPlayoutEvent ParsedRtcEventLog::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 ParsedRtcEventLog::GetLossBasedBweUpdate( - size_t index) const { - RTC_CHECK_LT(index, GetNumberOfEvents()); - const rtclog::Event& event = events_[index]; - return GetLossBasedBweUpdate(event); -} - -LoggedBweLossBasedUpdate ParsedRtcEventLog::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 ParsedRtcEventLog::GetDelayBasedBweUpdate( - size_t index) const { - RTC_CHECK_LT(index, GetNumberOfEvents()); - const rtclog::Event& event = events_[index]; - return GetDelayBasedBweUpdate(event); -} - -LoggedBweDelayBasedUpdate ParsedRtcEventLog::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 ParsedRtcEventLog::GetAudioNetworkAdaptation( - size_t index) const { - RTC_CHECK_LT(index, GetNumberOfEvents()); - const rtclog::Event& event = events_[index]; - return GetAudioNetworkAdaptation(event); -} - -LoggedAudioNetworkAdaptationEvent ParsedRtcEventLog::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 ParsedRtcEventLog::GetBweProbeClusterCreated( - size_t index) const { - RTC_CHECK_LT(index, GetNumberOfEvents()); - const rtclog::Event& event = events_[index]; - return GetBweProbeClusterCreated(event); -} - -LoggedBweProbeClusterCreatedEvent ParsedRtcEventLog::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; -} - -LoggedBweProbeResultEvent ParsedRtcEventLog::GetBweProbeResult( - size_t index) const { - RTC_CHECK_LT(index, GetNumberOfEvents()); - const rtclog::Event& event = events_[index]; - return GetBweProbeResult(event); -} - -LoggedBweProbeResultEvent ParsedRtcEventLog::GetBweProbeResult( - 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(); - LoggedBweProbeResultEvent 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::SUCCESS) { - RTC_CHECK(pr_event.has_bitrate_bps()); - res.bitrate_bps = pr_event.bitrate_bps(); - } else 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(); - } - - return res; -} - -LoggedAlrStateEvent ParsedRtcEventLog::GetAlrState(size_t index) const { - RTC_CHECK_LT(index, GetNumberOfEvents()); - const rtclog::Event& event = events_[index]; - return GetAlrState(event); -} - -LoggedAlrStateEvent ParsedRtcEventLog::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 ParsedRtcEventLog::GetIceCandidatePairConfig( - size_t index) const { - RTC_CHECK_LT(index, GetNumberOfEvents()); - const rtclog::Event& rtc_event = events_[index]; - return GetIceCandidatePairConfig(rtc_event); -} - -LoggedIceCandidatePairConfig ParsedRtcEventLog::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 ParsedRtcEventLog::GetIceCandidatePairEvent( - size_t index) const { - RTC_CHECK_LT(index, GetNumberOfEvents()); - const rtclog::Event& rtc_event = events_[index]; - return GetIceCandidatePairEvent(rtc_event); -} - -LoggedIceCandidatePairEvent ParsedRtcEventLog::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. -ParsedRtcEventLog::MediaType ParsedRtcEventLog::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 diff --git a/logging/rtc_event_log/rtc_event_log_parser2.h b/logging/rtc_event_log/rtc_event_log_parser2.h deleted file mode 100644 index dfc607d618..0000000000 --- a/logging/rtc_event_log/rtc_event_log_parser2.h +++ /dev/null @@ -1,920 +0,0 @@ -/* - * 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. - */ -#ifndef LOGGING_RTC_EVENT_LOG_RTC_EVENT_LOG_PARSER2_H_ -#define LOGGING_RTC_EVENT_LOG_RTC_EVENT_LOG_PARSER2_H_ - -#include -#include -#include -#include -#include // pair -#include - -#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" -#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h" -#include "modules/rtp_rtcp/include/rtp_header_extension_map.h" -#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" -#include "modules/rtp_rtcp/source/rtcp_packet/nack.h" -#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h" -#include "modules/rtp_rtcp/source/rtcp_packet/remb.h" -#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h" -#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h" -#include "rtc_base/ignore_wundef.h" - -// Files generated at build-time by the protobuf compiler. -RTC_PUSH_IGNORING_WUNDEF() -#ifdef WEBRTC_ANDROID_PLATFORM_BUILD -#include "external/webrtc/webrtc/logging/rtc_event_log/rtc_event_log.pb.h" -#else -#include "logging/rtc_event_log/rtc_event_log.pb.h" -#endif -RTC_POP_IGNORING_WUNDEF() - -namespace webrtc { - -enum class BandwidthUsage; -struct AudioEncoderRuntimeConfig; - -struct LoggedAlrStateEvent { - int64_t timestamp_us; - bool in_alr; - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } -}; - -struct LoggedAudioPlayoutEvent { - int64_t timestamp_us; - uint32_t ssrc; - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } -}; - -struct LoggedAudioNetworkAdaptationEvent { - int64_t timestamp_us; - AudioEncoderRuntimeConfig config; - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } -}; - -struct LoggedBweDelayBasedUpdate { - int64_t timestamp_us; - int32_t bitrate_bps; - BandwidthUsage detector_state; - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } -}; - -struct LoggedBweLossBasedUpdate { - int64_t timestamp_us; - int32_t bitrate_bps; - uint8_t fraction_lost; - int32_t expected_packets; - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } -}; - -struct LoggedBweProbeClusterCreatedEvent { - int64_t timestamp_us; - uint32_t id; - uint64_t bitrate_bps; - uint32_t min_packets; - uint32_t min_bytes; - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } -}; - -struct LoggedBweProbeResultEvent { - int64_t timestamp_us; - uint32_t id; - rtc::Optional bitrate_bps; - rtc::Optional failure_reason; - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } -}; - -struct LoggedIceCandidatePairConfig { - int64_t timestamp_us; - 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; - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } -}; - -struct LoggedIceCandidatePairEvent { - int64_t timestamp_us; - IceCandidatePairEventType type; - uint32_t candidate_pair_id; - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } -}; - -struct LoggedRtpPacket { - LoggedRtpPacket(uint64_t timestamp_us, - RTPHeader header, - size_t header_length, - size_t total_length) - : timestamp_us(timestamp_us), - header(header), - header_length(header_length), - total_length(total_length) {} - int64_t timestamp_us; - // TODO(terelius): This allocates space for 15 CSRCs even if none are used. - RTPHeader header; - size_t header_length; - size_t total_length; - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } -}; - -struct LoggedRtpPacketIncoming { - LoggedRtpPacketIncoming(uint64_t timestamp_us, - RTPHeader header, - size_t header_length, - size_t total_length) - : rtp(timestamp_us, header, header_length, total_length) {} - LoggedRtpPacket rtp; - int64_t log_time_us() const { return rtp.timestamp_us; } - int64_t log_time_ms() const { return rtp.timestamp_us / 1000; } -}; - -struct LoggedRtpPacketOutgoing { - LoggedRtpPacketOutgoing(uint64_t timestamp_us, - RTPHeader header, - size_t header_length, - size_t total_length) - : rtp(timestamp_us, header, header_length, total_length) {} - LoggedRtpPacket rtp; - int64_t log_time_us() const { return rtp.timestamp_us; } - int64_t log_time_ms() const { return rtp.timestamp_us / 1000; } -}; - -struct LoggedRtcpPacket { - LoggedRtcpPacket(uint64_t timestamp_us, - const uint8_t* packet, - size_t total_length) - : timestamp_us(timestamp_us), raw_data(packet, packet + total_length) {} - int64_t timestamp_us; - std::vector raw_data; - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } -}; - -struct LoggedRtcpPacketIncoming { - LoggedRtcpPacketIncoming(uint64_t timestamp_us, - const uint8_t* packet, - size_t total_length) - : rtcp(timestamp_us, packet, total_length) {} - LoggedRtcpPacket rtcp; - int64_t log_time_us() const { return rtcp.timestamp_us; } - int64_t log_time_ms() const { return rtcp.timestamp_us / 1000; } -}; - -struct LoggedRtcpPacketOutgoing { - LoggedRtcpPacketOutgoing(uint64_t timestamp_us, - const uint8_t* packet, - size_t total_length) - : rtcp(timestamp_us, packet, total_length) {} - LoggedRtcpPacket rtcp; - int64_t log_time_us() const { return rtcp.timestamp_us; } - int64_t log_time_ms() const { return rtcp.timestamp_us / 1000; } -}; - -struct LoggedRtcpPacketReceiverReport { - int64_t timestamp_us; - rtcp::ReceiverReport rr; - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } -}; - -struct LoggedRtcpPacketSenderReport { - int64_t timestamp_us; - rtcp::SenderReport sr; - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } -}; - -struct LoggedRtcpPacketRemb { - int64_t timestamp_us; - rtcp::Remb remb; - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } -}; - -struct LoggedRtcpPacketNack { - int64_t timestamp_us; - rtcp::Nack nack; - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } -}; - -struct LoggedRtcpPacketTransportFeedback { - int64_t timestamp_us; - rtcp::TransportFeedback transport_feedback; - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } -}; - -struct LoggedStartEvent { - explicit LoggedStartEvent(uint64_t timestamp_us) - : timestamp_us(timestamp_us) {} - int64_t timestamp_us; - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } -}; - -struct LoggedStopEvent { - explicit LoggedStopEvent(uint64_t timestamp_us) - : timestamp_us(timestamp_us) {} - int64_t timestamp_us; - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } -}; - -struct LoggedAudioRecvConfig { - LoggedAudioRecvConfig(int64_t timestamp_us, const rtclog::StreamConfig config) - : timestamp_us(timestamp_us), config(config) {} - int64_t timestamp_us; - rtclog::StreamConfig config; - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } -}; - -struct LoggedAudioSendConfig { - LoggedAudioSendConfig(int64_t timestamp_us, const rtclog::StreamConfig config) - : timestamp_us(timestamp_us), config(config) {} - int64_t timestamp_us; - rtclog::StreamConfig config; - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } -}; - -struct LoggedVideoRecvConfig { - LoggedVideoRecvConfig(int64_t timestamp_us, const rtclog::StreamConfig config) - : timestamp_us(timestamp_us), config(config) {} - int64_t timestamp_us; - rtclog::StreamConfig config; - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } -}; - -struct LoggedVideoSendConfig { - LoggedVideoSendConfig(int64_t timestamp_us, - const std::vector configs) - : timestamp_us(timestamp_us), configs(configs) {} - int64_t timestamp_us; - std::vector configs; - int64_t log_time_us() const { return timestamp_us; } - int64_t log_time_ms() const { return timestamp_us / 1000; } -}; - -template -class PacketView; - -template -class PacketIterator { - friend class PacketView; - - public: - // Standard iterator traits. - using difference_type = std::ptrdiff_t; - using value_type = T; - using pointer = T*; - using reference = T&; - using iterator_category = std::bidirectional_iterator_tag; - - // The default-contructed iterator is meaningless, but is required by the - // ForwardIterator concept. - PacketIterator() : ptr_(nullptr), element_size_(0) {} - PacketIterator(const PacketIterator& other) - : ptr_(other.ptr_), element_size_(other.element_size_) {} - PacketIterator(const PacketIterator&& other) - : ptr_(other.ptr_), element_size_(other.element_size_) {} - ~PacketIterator() = default; - - PacketIterator& operator=(const PacketIterator& other) { - ptr_ = other.ptr_; - element_size_ = other.element_size_; - return *this; - } - PacketIterator& operator=(const PacketIterator&& other) { - ptr_ = other.ptr_; - element_size_ = other.element_size_; - return *this; - } - - bool operator==(const PacketIterator& other) const { - RTC_DCHECK_EQ(element_size_, other.element_size_); - return ptr_ == other.ptr_; - } - bool operator!=(const PacketIterator& other) const { - RTC_DCHECK_EQ(element_size_, other.element_size_); - return ptr_ != other.ptr_; - } - - PacketIterator& operator++() { - ptr_ += element_size_; - return *this; - } - PacketIterator& operator--() { - ptr_ -= element_size_; - return *this; - } - PacketIterator operator++(int) { - PacketIterator iter_copy(ptr_, element_size_); - ptr_ += element_size_; - return iter_copy; - } - PacketIterator operator--(int) { - PacketIterator iter_copy(ptr_, element_size_); - ptr_ -= element_size_; - return iter_copy; - } - - T& operator*() { return *reinterpret_cast(ptr_); } - const T& operator*() const { return *reinterpret_cast(ptr_); } - - private: - PacketIterator(typename std::conditional::value, - const void*, - void*>::type p, - size_t s) - : ptr_(reinterpret_cast(p)), element_size_(s) {} - - typename std::conditional::value, const char*, char*>::type - ptr_; - size_t element_size_; -}; - -// Suppose that we have a struct S where we are only interested in a specific -// member M. Given an array of S, PacketView can be used to treat the array -// as an array of M, without exposing the type S to surrounding code and without -// accessing the member through a virtual function. In this case, we want to -// have a common view for incoming and outgoing RtpPackets, hence the PacketView -// name. -// Note that constructing a PacketView bypasses the typesystem, so the caller -// has to take extra care when constructing these objects. The implementation -// also requires that the containing struct is standard-layout (e.g. POD). -// -// Usage example: -// struct A {...}; -// struct B { A a; ...}; -// struct C { A a; ...}; -// size_t len = 10; -// B* array1 = new B[len]; -// C* array2 = new C[len]; -// -// PacketView view1 = PacketView::Create(array1, len, offsetof(B, a)); -// PacketView view2 = PacketView::Create(array2, len, offsetof(C, a)); -// -// The following code works with either view1 or view2. -// void f(PacketView view) -// for (A& a : view) { -// DoSomething(a); -// } -template -class PacketView { - public: - template - static PacketView Create(U* ptr, size_t num_elements, size_t offset) { - static_assert(std::is_standard_layout::value, - "PacketView can only be created for standard layout types."); - static_assert(std::is_standard_layout::value, - "PacketView can only be created for standard layout types."); - return PacketView(ptr, num_elements, offset, sizeof(U)); - } - - using iterator = PacketIterator; - using const_iterator = PacketIterator; - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::reverse_iterator; - - iterator begin() { return iterator(data_, element_size_); } - iterator end() { - auto end_ptr = data_ + num_elements_ * element_size_; - return iterator(end_ptr, element_size_); - } - - const_iterator begin() const { return const_iterator(data_, element_size_); } - const_iterator end() const { - auto end_ptr = data_ + num_elements_ * element_size_; - return const_iterator(end_ptr, element_size_); - } - - reverse_iterator rbegin() { return reverse_iterator(end()); } - reverse_iterator rend() { return reverse_iterator(begin()); } - - const_reverse_iterator rbegin() const { - return const_reverse_iterator(end()); - } - const_reverse_iterator rend() const { - return const_reverse_iterator(begin()); - } - - size_t size() const { return num_elements_; } - - T& operator[](size_t i) { - auto elem_ptr = data_ + i * element_size_; - return *reinterpret_cast(elem_ptr); - } - - const T& operator[](size_t i) const { - auto elem_ptr = data_ + i * element_size_; - return *reinterpret_cast(elem_ptr); - } - - private: - PacketView(typename std::conditional::value, - const void*, - void*>::type data, - size_t num_elements, - size_t offset, - size_t element_size) - : data_(reinterpret_cast(data) + offset), - num_elements_(num_elements), - element_size_(element_size) {} - - typename std::conditional::value, const char*, char*>::type - data_; - size_t num_elements_; - size_t element_size_; -}; - -class ParsedRtcEventLog { - friend class RtcEventLogTestHelper; - - public: - enum EventType { - UNKNOWN_EVENT = 0, - LOG_START = 1, - LOG_END = 2, - RTP_EVENT = 3, - RTCP_EVENT = 4, - AUDIO_PLAYOUT_EVENT = 5, - LOSS_BASED_BWE_UPDATE = 6, - DELAY_BASED_BWE_UPDATE = 7, - VIDEO_RECEIVER_CONFIG_EVENT = 8, - VIDEO_SENDER_CONFIG_EVENT = 9, - AUDIO_RECEIVER_CONFIG_EVENT = 10, - AUDIO_SENDER_CONFIG_EVENT = 11, - AUDIO_NETWORK_ADAPTATION_EVENT = 16, - 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, - }; - - enum class MediaType { ANY, AUDIO, VIDEO, DATA }; - enum class UnconfiguredHeaderExtensions { - kDontParse, - kAttemptWebrtcDefaultConfig - }; - - explicit ParsedRtcEventLog( - UnconfiguredHeaderExtensions parse_unconfigured_header_extensions = - UnconfiguredHeaderExtensions::kDontParse); - - // Clears previously parsed events and resets the ParsedRtcEventLog to an - // empty state. - void Clear(); - - // Reads an RtcEventLog file and returns true if parsing was successful. - bool ParseFile(const std::string& file_name); - - // Reads an RtcEventLog from a string and returns true if successful. - bool ParseString(const std::string& s); - - // Reads an RtcEventLog from an istream and returns true if successful. - bool ParseStream( - std::istream& stream); // no-presubmit-check TODO(webrtc:8982) - - // Returns the number of events in an EventStream. - size_t GetNumberOfEvents() const; - - // Reads the arrival timestamp (in microseconds) from a rtclog::Event. - int64_t GetTimestamp(size_t index) const; - int64_t GetTimestamp(const rtclog::Event& event) const; - - // Reads the event type of the rtclog::Event at |index|. - EventType GetEventType(size_t index) const; - - // Reads the header, direction, header length and packet length from the RTP - // event at |index|, and stores the values in the corresponding output - // parameters. Each output parameter can be set to nullptr if that value - // isn't needed. - // NB: The header must have space for at least IP_PACKET_SIZE bytes. - // Returns: a pointer to a header extensions map acquired from parsing - // corresponding Audio/Video Sender/Receiver config events. - // Warning: if the same SSRC is reused by both video and audio streams during - // call, extensions maps may be incorrect (the last one would be returned). - const webrtc::RtpHeaderExtensionMap* GetRtpHeader( - size_t index, - PacketDirection* incoming, - uint8_t* header, - size_t* header_length, - size_t* total_length, - int* probe_cluster_id) const; - const webrtc::RtpHeaderExtensionMap* GetRtpHeader( - const rtclog::Event& event, - PacketDirection* incoming, - uint8_t* header, - size_t* header_length, - size_t* total_length, - int* probe_cluster_id) const; - - // Reads packet, direction and packet length from the RTCP event at |index|, - // and stores the values in the corresponding output parameters. - // Each output parameter can be set to nullptr if that value isn't needed. - // NB: The packet must have space for at least IP_PACKET_SIZE bytes. - void GetRtcpPacket(size_t index, - PacketDirection* incoming, - uint8_t* packet, - size_t* length) const; - void GetRtcpPacket(const rtclog::Event& event, - PacketDirection* incoming, - uint8_t* packet, - size_t* length) const; - - // Reads a video receive config event to a StreamConfig struct. - // Only the fields that are stored in the protobuf will be written. - rtclog::StreamConfig GetVideoReceiveConfig(size_t index) const; - - // Reads a video send config event to a StreamConfig struct. If the proto - // contains multiple SSRCs and RTX SSRCs (this used to be the case for - // simulcast streams) then we return one StreamConfig per SSRC,RTX_SSRC pair. - // Only the fields that are stored in the protobuf will be written. - std::vector GetVideoSendConfig(size_t index) const; - - // Reads a audio receive config event to a StreamConfig struct. - // Only the fields that are stored in the protobuf will be written. - rtclog::StreamConfig GetAudioReceiveConfig(size_t index) const; - - // Reads a config event to a StreamConfig struct. - // Only the fields that are stored in the protobuf will be written. - rtclog::StreamConfig GetAudioSendConfig(size_t index) const; - - // Reads the SSRC from the audio playout event at |index|. The SSRC is stored - // in the output parameter ssrc. The output parameter can be set to nullptr - // and in that case the function only asserts that the event is well formed. - LoggedAudioPlayoutEvent GetAudioPlayout(size_t index) const; - - // Reads bitrate, fraction loss (as defined in RFC 1889) and total number of - // expected packets from the loss based BWE event at |index| and stores the - // values in - // the corresponding output parameters. Each output parameter can be set to - // nullptr if that - // value isn't needed. - LoggedBweLossBasedUpdate GetLossBasedBweUpdate(size_t index) const; - - // Reads bitrate and detector_state from the delay based BWE event at |index| - // and stores the values in the corresponding output parameters. Each output - // parameter can be set to nullptr if that - // value isn't needed. - LoggedBweDelayBasedUpdate GetDelayBasedBweUpdate(size_t index) const; - - // Reads a audio network adaptation event to a (non-NULL) - // AudioEncoderRuntimeConfig struct. Only the fields that are - // stored in the protobuf will be written. - LoggedAudioNetworkAdaptationEvent GetAudioNetworkAdaptation( - size_t index) const; - - LoggedBweProbeClusterCreatedEvent GetBweProbeClusterCreated( - size_t index) const; - - LoggedBweProbeResultEvent GetBweProbeResult(size_t index) const; - - MediaType GetMediaType(uint32_t ssrc, PacketDirection direction) const; - - LoggedAlrStateEvent GetAlrState(size_t index) const; - - LoggedIceCandidatePairConfig GetIceCandidatePairConfig(size_t index) const; - - LoggedIceCandidatePairEvent GetIceCandidatePairEvent(size_t index) const; - - const std::set& incoming_rtx_ssrcs() const { - return incoming_rtx_ssrcs_; - } - const std::set& incoming_video_ssrcs() const { - return incoming_video_ssrcs_; - } - const std::set& incoming_audio_ssrcs() const { - return incoming_audio_ssrcs_; - } - const std::set& outgoing_rtx_ssrcs() const { - return outgoing_rtx_ssrcs_; - } - const std::set& outgoing_video_ssrcs() const { - return outgoing_video_ssrcs_; - } - const std::set& outgoing_audio_ssrcs() const { - return outgoing_audio_ssrcs_; - } - - const std::vector& start_log_events() const { - return start_log_events_; - } - const std::vector& stop_log_events() const { - return stop_log_events_; - } - const std::map>& audio_playout_events() const { - return audio_playout_events_; - } - const std::vector& - audio_network_adaptation_events() const { - return audio_network_adaptation_events_; - } - const std::vector& - bwe_probe_cluster_created_events() const { - return bwe_probe_cluster_created_events_; - } - const std::vector& bwe_probe_result_events() - const { - return bwe_probe_result_events_; - } - const std::vector& bwe_delay_updates() const { - return bwe_delay_updates_; - } - const std::vector& bwe_loss_updates() const { - return bwe_loss_updates_; - } - const std::vector& alr_state_events() const { - return alr_state_events_; - } - const std::vector& ice_candidate_pair_configs() - const { - return ice_candidate_pair_configs_; - } - const std::vector& ice_candidate_pair_events() - const { - return ice_candidate_pair_events_; - } - - struct LoggedRtpStreamIncoming { - uint32_t ssrc; - std::vector incoming_packets; - }; - - struct LoggedRtpStreamOutgoing { - uint32_t ssrc; - std::vector outgoing_packets; - }; - - struct LoggedRtpStreamView { - LoggedRtpStreamView(uint32_t ssrc, - const LoggedRtpPacketIncoming* ptr, - size_t num_elements) - : ssrc(ssrc), - packet_view(PacketView::Create( - ptr, - num_elements, - offsetof(LoggedRtpPacketIncoming, rtp))) {} - LoggedRtpStreamView(uint32_t ssrc, - const LoggedRtpPacketOutgoing* ptr, - size_t num_elements) - : ssrc(ssrc), - packet_view(PacketView::Create( - ptr, - num_elements, - offsetof(LoggedRtpPacketOutgoing, rtp))) {} - uint32_t ssrc; - PacketView packet_view; - }; - - const std::vector& incoming_rtp_packets_by_ssrc() - const { - return incoming_rtp_packets_by_ssrc_; - } - - const std::vector& outgoing_rtp_packets_by_ssrc() - const { - return outgoing_rtp_packets_by_ssrc_; - } - - const std::vector& incoming_rtcp_packets() const { - return incoming_rtcp_packets_; - } - - const std::vector& outgoing_rtcp_packets() const { - return outgoing_rtcp_packets_; - } - - const std::vector& rtp_packets_by_ssrc( - PacketDirection direction) const { - if (direction == kIncomingPacket) - return incoming_rtp_packet_views_by_ssrc_; - else - return outgoing_rtp_packet_views_by_ssrc_; - } - - const std::vector& receiver_reports( - PacketDirection direction) const { - if (direction == kIncomingPacket) { - return incoming_rr_; - } else { - return outgoing_rr_; - } - } - - const std::vector& sender_reports( - PacketDirection direction) const { - if (direction == kIncomingPacket) { - return incoming_sr_; - } else { - return outgoing_sr_; - } - } - - const std::vector& nacks( - PacketDirection direction) const { - if (direction == kIncomingPacket) { - return incoming_nack_; - } else { - return outgoing_nack_; - } - } - - const std::vector& rembs( - PacketDirection direction) const { - if (direction == kIncomingPacket) { - return incoming_remb_; - } else { - return outgoing_remb_; - } - } - - const std::vector& transport_feedbacks( - PacketDirection direction) const { - if (direction == kIncomingPacket) { - return incoming_transport_feedback_; - } else { - return outgoing_transport_feedback_; - } - } - - int64_t first_timestamp() const { return first_timestamp_; } - int64_t last_timestamp() const { return last_timestamp_; } - - private: - void StoreParsedEvent(const rtclog::Event& event); - - rtclog::StreamConfig GetVideoReceiveConfig(const rtclog::Event& event) const; - std::vector GetVideoSendConfig( - const rtclog::Event& event) const; - rtclog::StreamConfig GetAudioReceiveConfig(const rtclog::Event& event) const; - rtclog::StreamConfig GetAudioSendConfig(const rtclog::Event& event) const; - - LoggedAudioPlayoutEvent GetAudioPlayout(const rtclog::Event& event) const; - - LoggedBweLossBasedUpdate GetLossBasedBweUpdate( - const rtclog::Event& event) const; - LoggedBweDelayBasedUpdate GetDelayBasedBweUpdate( - const rtclog::Event& event) const; - - LoggedAudioNetworkAdaptationEvent GetAudioNetworkAdaptation( - const rtclog::Event& event) const; - - LoggedBweProbeClusterCreatedEvent GetBweProbeClusterCreated( - const rtclog::Event& event) const; - LoggedBweProbeResultEvent GetBweProbeResult(const rtclog::Event& event) const; - - LoggedAlrStateEvent GetAlrState(const rtclog::Event& event) const; - - LoggedIceCandidatePairConfig GetIceCandidatePairConfig( - const rtclog::Event& event) const; - LoggedIceCandidatePairEvent GetIceCandidatePairEvent( - const rtclog::Event& event) const; - - std::vector events_; - - struct Stream { - Stream(uint32_t ssrc, - MediaType media_type, - PacketDirection direction, - webrtc::RtpHeaderExtensionMap map) - : ssrc(ssrc), - media_type(media_type), - direction(direction), - rtp_extensions_map(map) {} - uint32_t ssrc; - MediaType media_type; - PacketDirection direction; - webrtc::RtpHeaderExtensionMap rtp_extensions_map; - }; - - const UnconfiguredHeaderExtensions parse_unconfigured_header_extensions_; - - // Make a default extension map for streams without configuration information. - // TODO(ivoc): Once configuration of audio streams is stored in the event log, - // this can be removed. Tracking bug: webrtc:6399 - RtpHeaderExtensionMap default_extension_map_; - - // Tracks what each stream is configured for. Note that a single SSRC can be - // in several sets. For example, the SSRC used for sending video over RTX - // will appear in both video_ssrcs_ and rtx_ssrcs_. In the unlikely case that - // an SSRC is reconfigured to a different media type mid-call, it will also - // appear in multiple sets. - std::set incoming_rtx_ssrcs_; - std::set incoming_video_ssrcs_; - std::set incoming_audio_ssrcs_; - std::set outgoing_rtx_ssrcs_; - std::set outgoing_video_ssrcs_; - std::set outgoing_audio_ssrcs_; - - // Maps an SSRC to the parsed RTP headers in that stream. Header extensions - // are parsed if the stream has been configured. This is only used for - // grouping the events by SSRC during parsing; the events are moved to - // incoming_rtp_packets_by_ssrc_ once the parsing is done. - std::map> - incoming_rtp_packets_map_; - std::map> - outgoing_rtp_packets_map_; - - // RTP headers. - std::vector incoming_rtp_packets_by_ssrc_; - std::vector outgoing_rtp_packets_by_ssrc_; - std::vector incoming_rtp_packet_views_by_ssrc_; - std::vector outgoing_rtp_packet_views_by_ssrc_; - - // Raw RTCP packets. - std::vector incoming_rtcp_packets_; - std::vector outgoing_rtcp_packets_; - - // Parsed RTCP messages. Currently not separated based on SSRC. - std::vector incoming_rr_; - std::vector outgoing_rr_; - std::vector incoming_sr_; - std::vector outgoing_sr_; - std::vector incoming_nack_; - std::vector outgoing_nack_; - std::vector incoming_remb_; - std::vector outgoing_remb_; - std::vector incoming_transport_feedback_; - std::vector outgoing_transport_feedback_; - - std::vector start_log_events_; - std::vector stop_log_events_; - - // Maps an SSRC to the timestamps of parsed audio playout events. - std::map> audio_playout_events_; - - std::vector - audio_network_adaptation_events_; - - std::vector - bwe_probe_cluster_created_events_; - - std::vector bwe_probe_result_events_; - - std::vector bwe_delay_updates_; - - // A list of all updates from the send-side loss-based bandwidth estimator. - std::vector bwe_loss_updates_; - - std::vector alr_state_events_; - - std::vector ice_candidate_pair_configs_; - - std::vector ice_candidate_pair_events_; - - std::vector audio_recv_configs_; - std::vector audio_send_configs_; - std::vector video_recv_configs_; - std::vector video_send_configs_; - - uint8_t last_incoming_rtcp_packet_[IP_PACKET_SIZE]; - uint8_t last_incoming_rtcp_packet_length_; - - int64_t first_timestamp_; - int64_t last_timestamp_; - - // The extension maps are mutable to allow us to insert the default - // configuration when parsing an RTP header for an unconfigured stream. - mutable std::map - incoming_rtp_extensions_maps_; - mutable std::map - outgoing_rtp_extensions_maps_; -}; - -} // namespace webrtc - -#endif // LOGGING_RTC_EVENT_LOG_RTC_EVENT_LOG_PARSER2_H_ diff --git a/logging/rtc_event_log/rtc_event_log_unittest.cc b/logging/rtc_event_log/rtc_event_log_unittest.cc index 529228bc4f..1cea3138ab 100644 --- a/logging/rtc_event_log/rtc_event_log_unittest.cc +++ b/logging/rtc_event_log/rtc_event_log_unittest.cc @@ -34,7 +34,7 @@ #include "logging/rtc_event_log/events/rtc_event_video_send_stream_config.h" #include "logging/rtc_event_log/output/rtc_event_log_output_file.h" #include "logging/rtc_event_log/rtc_event_log.h" -#include "logging/rtc_event_log/rtc_event_log_parser2.h" +#include "logging/rtc_event_log/rtc_event_log_parser.h" #include "logging/rtc_event_log/rtc_event_log_unittest_helper.h" #include "logging/rtc_event_log/rtc_stream_config.h" #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h" @@ -750,16 +750,17 @@ TEST(RtcEventLogTest, CircularBufferKeepsMostRecentEvents) { for (size_t i = 1; i < parsed_log.GetNumberOfEvents() - 1; i++) { EXPECT_EQ(parsed_log.GetEventType(i), ParsedRtcEventLog::EventType::AUDIO_PLAYOUT_EVENT); - LoggedAudioPlayoutEvent playout_event = parsed_log.GetAudioPlayout(i); - EXPECT_LT(playout_event.ssrc, kNumEvents); - EXPECT_EQ(static_cast(kStartTime + 10000 * playout_event.ssrc), - playout_event.timestamp_us); + uint32_t ssrc; + parsed_log.GetAudioPlayout(i, &ssrc); + int64_t timestamp = parsed_log.GetTimestamp(i); + EXPECT_LT(ssrc, kNumEvents); + EXPECT_EQ(static_cast(kStartTime + 10000 * ssrc), timestamp); if (last_ssrc) - EXPECT_EQ(playout_event.ssrc, *last_ssrc + 1); + EXPECT_EQ(ssrc, *last_ssrc + 1); if (last_timestamp) - EXPECT_EQ(playout_event.timestamp_us, *last_timestamp + 10000); - last_ssrc = playout_event.ssrc; - last_timestamp = playout_event.timestamp_us; + EXPECT_EQ(timestamp, *last_timestamp + 10000); + last_ssrc = ssrc; + last_timestamp = timestamp; } RtcEventLogTestHelper::VerifyLogEndEvent(parsed_log, parsed_log.GetNumberOfEvents() - 1); diff --git a/logging/rtc_event_log/rtc_event_log_unittest_helper.cc b/logging/rtc_event_log/rtc_event_log_unittest_helper.cc index 955c3b98e8..23e15b5033 100644 --- a/logging/rtc_event_log/rtc_event_log_unittest_helper.cc +++ b/logging/rtc_event_log/rtc_event_log_unittest_helper.cc @@ -460,8 +460,9 @@ void RtcEventLogTestHelper::VerifyPlayoutEvent( EXPECT_EQ(ssrc, playout_event.local_ssrc()); // Check consistency of the parser. - LoggedAudioPlayoutEvent parsed_event = parsed_log.GetAudioPlayout(index); - EXPECT_EQ(ssrc, parsed_event.ssrc); + uint32_t parsed_ssrc; + parsed_log.GetAudioPlayout(index, &parsed_ssrc); + EXPECT_EQ(ssrc, parsed_ssrc); } void RtcEventLogTestHelper::VerifyBweLossEvent( @@ -483,10 +484,14 @@ void RtcEventLogTestHelper::VerifyBweLossEvent( EXPECT_EQ(total_packets, bwe_event.total_packets()); // Check consistency of the parser. - LoggedBweLossBasedUpdate bwe_update = parsed_log.GetLossBasedBweUpdate(index); - EXPECT_EQ(bitrate, bwe_update.bitrate_bps); - EXPECT_EQ(fraction_loss, bwe_update.fraction_lost); - EXPECT_EQ(total_packets, bwe_update.expected_packets); + int32_t parsed_bitrate; + uint8_t parsed_fraction_loss; + int32_t parsed_total_packets; + parsed_log.GetLossBasedBweUpdate( + index, &parsed_bitrate, &parsed_fraction_loss, &parsed_total_packets); + EXPECT_EQ(bitrate, parsed_bitrate); + EXPECT_EQ(fraction_loss, parsed_fraction_loss); + EXPECT_EQ(total_packets, parsed_total_packets); } void RtcEventLogTestHelper::VerifyBweDelayEvent( @@ -506,7 +511,8 @@ void RtcEventLogTestHelper::VerifyBweDelayEvent( GetRuntimeDetectorState(bwe_event.detector_state())); // Check consistency of the parser. - LoggedBweDelayBasedUpdate res = parsed_log.GetDelayBasedBweUpdate(index); + ParsedRtcEventLog::BweDelayBasedUpdate res = + parsed_log.GetDelayBasedBweUpdate(index); EXPECT_EQ(res.bitrate_bps, bitrate); EXPECT_EQ(res.detector_state, detector_state); } @@ -515,20 +521,15 @@ void RtcEventLogTestHelper::VerifyAudioNetworkAdaptation( const ParsedRtcEventLog& parsed_log, size_t index, const AudioEncoderRuntimeConfig& config) { - ASSERT_LT(index, parsed_log.events_.size()); - const rtclog::Event& event = parsed_log.events_[index]; - ASSERT_TRUE(IsValidBasicEvent(event)); - ASSERT_EQ(rtclog::Event::AUDIO_NETWORK_ADAPTATION_EVENT, event.type()); - - LoggedAudioNetworkAdaptationEvent parsed_event = - parsed_log.GetAudioNetworkAdaptation(index); - EXPECT_EQ(config.bitrate_bps, parsed_event.config.bitrate_bps); - EXPECT_EQ(config.enable_dtx, parsed_event.config.enable_dtx); - EXPECT_EQ(config.enable_fec, parsed_event.config.enable_fec); - EXPECT_EQ(config.frame_length_ms, parsed_event.config.frame_length_ms); - EXPECT_EQ(config.num_channels, parsed_event.config.num_channels); + AudioEncoderRuntimeConfig parsed_config; + parsed_log.GetAudioNetworkAdaptation(index, &parsed_config); + EXPECT_EQ(config.bitrate_bps, parsed_config.bitrate_bps); + EXPECT_EQ(config.enable_dtx, parsed_config.enable_dtx); + EXPECT_EQ(config.enable_fec, parsed_config.enable_fec); + EXPECT_EQ(config.frame_length_ms, parsed_config.frame_length_ms); + EXPECT_EQ(config.num_channels, parsed_config.num_channels); EXPECT_EQ(config.uplink_packet_loss_fraction, - parsed_event.config.uplink_packet_loss_fraction); + parsed_config.uplink_packet_loss_fraction); } void RtcEventLogTestHelper::VerifyLogStartEvent( diff --git a/logging/rtc_event_log/rtc_event_log_unittest_helper.h b/logging/rtc_event_log/rtc_event_log_unittest_helper.h index 949a3db8a2..630f160a18 100644 --- a/logging/rtc_event_log/rtc_event_log_unittest_helper.h +++ b/logging/rtc_event_log/rtc_event_log_unittest_helper.h @@ -12,7 +12,7 @@ #define LOGGING_RTC_EVENT_LOG_RTC_EVENT_LOG_UNITTEST_HELPER_H_ #include "call/call.h" -#include "logging/rtc_event_log/rtc_event_log_parser2.h" +#include "logging/rtc_event_log/rtc_event_log_parser.h" #include "modules/rtp_rtcp/source/rtp_packet_received.h" #include "modules/rtp_rtcp/source/rtp_packet_to_send.h" diff --git a/modules/audio_coding/neteq/tools/rtc_event_log_source.cc b/modules/audio_coding/neteq/tools/rtc_event_log_source.cc index b370e8898a..d6224ffa0e 100644 --- a/modules/audio_coding/neteq/tools/rtc_event_log_source.cc +++ b/modules/audio_coding/neteq/tools/rtc_event_log_source.cc @@ -66,7 +66,7 @@ std::unique_ptr RtcEventLogSource::NextPacket() { } if (parsed_stream_.GetMediaType(packet->header().ssrc, direction) != - ParsedRtcEventLog::MediaType::AUDIO) { + webrtc::ParsedRtcEventLog::MediaType::AUDIO) { continue; } @@ -85,10 +85,12 @@ int64_t RtcEventLogSource::NextAudioOutputEventMs() { while (audio_output_index_ < parsed_stream_.GetNumberOfEvents()) { if (parsed_stream_.GetEventType(audio_output_index_) == ParsedRtcEventLog::AUDIO_PLAYOUT_EVENT) { - LoggedAudioPlayoutEvent playout_event = - parsed_stream_.GetAudioPlayout(audio_output_index_); + uint64_t timestamp_us = parsed_stream_.GetTimestamp(audio_output_index_); + // We call GetAudioPlayout only to check that the protobuf event is + // well-formed. + parsed_stream_.GetAudioPlayout(audio_output_index_, nullptr); audio_output_index_++; - return playout_event.timestamp_us / 1000; + return timestamp_us / 1000; } audio_output_index_++; } diff --git a/modules/audio_coding/neteq/tools/rtc_event_log_source.h b/modules/audio_coding/neteq/tools/rtc_event_log_source.h index 1b25e1239c..df01e06535 100644 --- a/modules/audio_coding/neteq/tools/rtc_event_log_source.h +++ b/modules/audio_coding/neteq/tools/rtc_event_log_source.h @@ -14,7 +14,7 @@ #include #include -#include "logging/rtc_event_log/rtc_event_log_parser2.h" +#include "logging/rtc_event_log/rtc_event_log_parser.h" #include "modules/audio_coding/neteq/tools/packet_source.h" #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" #include "rtc_base/constructormagic.h" diff --git a/rtc_tools/BUILD.gn b/rtc_tools/BUILD.gn index 73e2494d1e..d1d2b55dd4 100644 --- a/rtc_tools/BUILD.gn +++ b/rtc_tools/BUILD.gn @@ -237,7 +237,6 @@ if (!build_with_chromium) { "../rtc_base:checks", "../rtc_base:rtc_base_approved", "../rtc_base:rtc_numerics", - "../rtc_base:stringutils", # TODO(kwiberg): Remove this dependency. "../api/audio_codecs:audio_codecs_api", diff --git a/rtc_tools/event_log_visualizer/analyzer.cc b/rtc_tools/event_log_visualizer/analyzer.cc index c7806324f4..1a7309c4e1 100644 --- a/rtc_tools/event_log_visualizer/analyzer.cc +++ b/rtc_tools/event_log_visualizer/analyzer.cc @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -24,7 +25,6 @@ #include "call/video_send_stream.h" #include "common_types.h" // NOLINT(build/include) #include "logging/rtc_event_log/rtc_stream_config.h" -#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h" #include "modules/audio_coding/neteq/tools/audio_sink.h" #include "modules/audio_coding/neteq/tools/fake_decode_from_file.h" #include "modules/audio_coding/neteq/tools/neteq_delay_analyzer.h" @@ -40,7 +40,6 @@ #include "modules/pacing/packet_router.h" #include "modules/rtp_rtcp/include/rtp_rtcp.h" #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" -#include "modules/rtp_rtcp/source/rtcp_packet.h" #include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" #include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h" #include "modules/rtp_rtcp/source/rtcp_packet/remb.h" @@ -50,7 +49,6 @@ #include "modules/rtp_rtcp/source/rtp_utility.h" #include "rtc_base/checks.h" #include "rtc_base/format_macros.h" -#include "rtc_base/function_view.h" #include "rtc_base/logging.h" #include "rtc_base/numerics/sequence_number_util.h" #include "rtc_base/ptr_util.h" @@ -61,6 +59,7 @@ #endif // BWE_TEST_LOGGING_COMPILE_TIME_ENABLE namespace webrtc { +namespace plotting { namespace { @@ -128,45 +127,29 @@ int64_t WrappingDifference(uint32_t later, uint32_t earlier, int64_t modulus) { return difference; } -// This is much more reliable for outgoing streams than for incoming streams. -template -rtc::Optional EstimateRtpClockFrequency( - const RtpPacketContainer& packets, - int64_t end_time_us) { - RTC_CHECK(packets.size() >= 2); - SeqNumUnwrapper unwrapper; - uint64_t first_rtp_timestamp = - unwrapper.Unwrap(packets[0].rtp.header.timestamp); - int64_t first_log_timestamp = packets[0].log_time_us(); - uint64_t last_rtp_timestamp = first_rtp_timestamp; - int64_t last_log_timestamp = first_log_timestamp; - for (size_t i = 1; i < packets.size(); i++) { - if (packets[i].log_time_us() > end_time_us) - break; - last_rtp_timestamp = unwrapper.Unwrap(packets[i].rtp.header.timestamp); - last_log_timestamp = packets[i].log_time_us(); - } - if (last_log_timestamp - first_log_timestamp < kNumMicrosecsPerSec) { - RTC_LOG(LS_WARNING) - << "Failed to estimate RTP clock frequency: Stream too short. (" - << packets.size() << " packets, " - << last_log_timestamp - first_log_timestamp << " us)"; - return rtc::nullopt; - } - double duration = - 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}) { - if (std::fabs(estimated_frequency - f) < 0.05 * f) { - return f; - } - } - RTC_LOG(LS_WARNING) << "Failed to estimate RTP clock frequency: Estimate " - << estimated_frequency - << "not close to any stardard RTP frequency."; - return rtc::nullopt; +// 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(webrtc::RtpExtension::kAudioLevelDefaultId); + default_map.Register( + webrtc::RtpExtension::kTimestampOffsetDefaultId); + default_map.Register( + webrtc::RtpExtension::kAbsSendTimeDefaultId); + default_map.Register( + webrtc::RtpExtension::kVideoRotationDefaultId); + default_map.Register( + webrtc::RtpExtension::kVideoContentTypeDefaultId); + default_map.Register( + webrtc::RtpExtension::kVideoTimingDefaultId); + default_map.Register( + webrtc::RtpExtension::kTransportSequenceNumberDefaultId); + default_map.Register( + webrtc::RtpExtension::kPlayoutDelayDefaultId); + return default_map; } constexpr float kLeftMargin = 0.01f; @@ -182,8 +165,7 @@ rtc::Optional NetworkDelayDiff_AbsSendTime( int64_t send_time_diff = WrappingDifference( new_packet.header.extension.absoluteSendTime, old_packet.header.extension.absoluteSendTime, 1ul << 24); - int64_t recv_time_diff = - new_packet.log_time_us() - old_packet.log_time_us(); + int64_t recv_time_diff = new_packet.timestamp - old_packet.timestamp; double delay_change_us = recv_time_diff - AbsSendTimeToMicroseconds(send_time_diff); return delay_change_us / 1000; @@ -197,7 +179,7 @@ rtc::Optional NetworkDelayDiff_CaptureTime( const LoggedRtpPacket& new_packet) { int64_t send_time_diff = WrappingDifference( new_packet.header.timestamp, old_packet.header.timestamp, 1ull << 32); - int64_t recv_time_diff = new_packet.log_time_us() - old_packet.log_time_us(); + int64_t recv_time_diff = new_packet.timestamp - old_packet.timestamp; const double kVideoSampleRate = 90000; // TODO(terelius): We treat all streams as video for now, even though @@ -211,9 +193,9 @@ rtc::Optional NetworkDelayDiff_CaptureTime( if (delay_change < -10000 || 10000 < delay_change) { RTC_LOG(LS_WARNING) << "Very large delay change. Timestamps correct?"; RTC_LOG(LS_WARNING) << "Old capture time " << old_packet.header.timestamp - << ", received time " << old_packet.log_time_us(); + << ", received time " << old_packet.timestamp; RTC_LOG(LS_WARNING) << "New capture time " << new_packet.header.timestamp - << ", received time " << new_packet.log_time_us(); + << ", received time " << new_packet.timestamp; RTC_LOG(LS_WARNING) << "Receive time difference " << recv_time_diff << " = " << static_cast(recv_time_diff) / kNumMicrosecsPerSec @@ -226,55 +208,55 @@ rtc::Optional NetworkDelayDiff_CaptureTime( return delay_change; } -// For each element in data_view, use |f()| to extract a y-coordinate and +// For each element in data, use |get_y()| to extract a y-coordinate and // store the result in a TimeSeries. -template -void ProcessPoints(rtc::FunctionView(const DataType&)> f, - const IterableType& data_view, - int64_t begin_time, - TimeSeries* result) { - for (size_t i = 0; i < data_view.size(); i++) { - const DataType& elem = data_view[i]; - float x = static_cast(elem.log_time_us() - begin_time) / +template +void ProcessPoints( + rtc::FunctionView(const DataType&)> get_y, + const std::vector& data, + uint64_t begin_time, + TimeSeries* result) { + for (size_t i = 0; i < data.size(); i++) { + float x = static_cast(data[i].timestamp - begin_time) / kNumMicrosecsPerSec; - rtc::Optional y = f(elem); + rtc::Optional y = get_y(data[i]); if (y) result->points.emplace_back(x, *y); } } -// For each pair of adjacent elements in |data|, use |f()| to extract a +// For each pair of adjacent elements in |data|, use |get_y| to extract a // y-coordinate and store the result in a TimeSeries. Note that the x-coordinate // will be the time of the second element in the pair. -template +template void ProcessPairs( rtc::FunctionView(const DataType&, - const DataType&)> f, - const IterableType& data, - int64_t begin_time, + const DataType&)> get_y, + const std::vector& data, + uint64_t begin_time, TimeSeries* result) { for (size_t i = 1; i < data.size(); i++) { - float x = static_cast(data[i].log_time_us() - begin_time) / + float x = static_cast(data[i].timestamp - begin_time) / kNumMicrosecsPerSec; - rtc::Optional y = f(data[i - 1], data[i]); + rtc::Optional y = get_y(data[i - 1], data[i]); if (y) result->points.emplace_back(x, static_cast(*y)); } } -// For each element in data, use |f()| to extract a y-coordinate and +// For each element in data, use |extract()| to extract a y-coordinate and // store the result in a TimeSeries. -template +template void AccumulatePoints( - rtc::FunctionView(const DataType&)> f, - const IterableType& data, - int64_t begin_time, + rtc::FunctionView(const DataType&)> extract, + const std::vector& data, + uint64_t begin_time, TimeSeries* result) { ResultType sum = 0; for (size_t i = 0; i < data.size(); i++) { - float x = static_cast(data[i].log_time_us() - begin_time) / + float x = static_cast(data[i].timestamp - begin_time) / kNumMicrosecsPerSec; - rtc::Optional y = f(data[i]); + rtc::Optional y = extract(data[i]); if (y) { sum += *y; result->points.emplace_back(x, static_cast(sum)); @@ -282,21 +264,21 @@ void AccumulatePoints( } } -// For each pair of adjacent elements in |data|, use |f()| to extract a +// For each pair of adjacent elements in |data|, use |extract()| to extract a // y-coordinate and store the result in a TimeSeries. Note that the x-coordinate // will be the time of the second element in the pair. -template +template void AccumulatePairs( rtc::FunctionView(const DataType&, - const DataType&)> f, - const IterableType& data, - int64_t begin_time, + const DataType&)> extract, + const std::vector& data, + uint64_t begin_time, TimeSeries* result) { ResultType sum = 0; for (size_t i = 1; i < data.size(); i++) { - float x = static_cast(data[i].log_time_us() - begin_time) / + float x = static_cast(data[i].timestamp - begin_time) / kNumMicrosecsPerSec; - rtc::Optional y = f(data[i - 1], data[i]); + rtc::Optional y = extract(data[i - 1], data[i]); if (y) sum += *y; result->points.emplace_back(x, static_cast(sum)); @@ -307,31 +289,30 @@ void AccumulatePairs( // A data point is generated every |step| microseconds from |begin_time| // to |end_time|. The value of each data point is the average of the data // during the preceeding |window_duration_us| microseconds. -template +template void MovingAverage( - rtc::FunctionView(const DataType&)> f, - const IterableType& data_view, - int64_t begin_time, - int64_t end_time, - int64_t window_duration_us, - int64_t step, - TimeSeries* result) { + rtc::FunctionView(const DataType&)> extract, + const std::vector& data, + uint64_t begin_time, + uint64_t end_time, + uint64_t window_duration_us, + uint64_t step, + webrtc::plotting::TimeSeries* result) { size_t window_index_begin = 0; size_t window_index_end = 0; ResultType sum_in_window = 0; - for (int64_t t = begin_time; t < end_time + step; t += step) { - while (window_index_end < data_view.size() && - data_view[window_index_end].log_time_us() < t) { - rtc::Optional value = f(data_view[window_index_end]); + for (uint64_t t = begin_time; t < end_time + step; t += step) { + while (window_index_end < data.size() && + data[window_index_end].timestamp < t) { + rtc::Optional value = extract(data[window_index_end]); if (value) sum_in_window += *value; ++window_index_end; } - while (window_index_begin < data_view.size() && - data_view[window_index_begin].log_time_us() < - t - window_duration_us) { - rtc::Optional value = f(data_view[window_index_begin]); + while (window_index_begin < data.size() && + data[window_index_begin].timestamp < t - window_duration_us) { + rtc::Optional value = extract(data[window_index_begin]); if (value) sum_in_window -= *value; ++window_index_begin; @@ -425,7 +406,7 @@ std::string GetNetworkTypeAsString(webrtc::IceCandidateNetworkType type) { } std::string GetCandidatePairLogDescriptionAsString( - const LoggedIceCandidatePairConfig& config) { + 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 @@ -448,57 +429,244 @@ std::string GetCandidatePairLogDescriptionAsString( return ss.str(); } -std::string GetDirectionAsString(PacketDirection direction) { - if (direction == kIncomingPacket) { - return "Incoming"; - } else { - return "Outgoing"; - } -} - -std::string GetDirectionAsShortString(PacketDirection direction) { - if (direction == kIncomingPacket) { - return "In"; - } else { - return "Out"; - } -} - } // namespace EventLogAnalyzer::EventLogAnalyzer(const ParsedRtcEventLog& log) : parsed_log_(log), window_duration_(250000), step_(10000) { - begin_time_ = parsed_log_.first_timestamp(); - end_time_ = parsed_log_.last_timestamp(); - if (end_time_ < begin_time_) { - RTC_LOG(LS_WARNING) << "No useful events in the log."; - begin_time_ = end_time_ = 0; - } - call_duration_s_ = ToCallTime(end_time_); + uint64_t first_timestamp = std::numeric_limits::max(); + uint64_t last_timestamp = std::numeric_limits::min(); - const auto& log_start_events = parsed_log_.start_log_events(); - const auto& log_end_events = parsed_log_.stop_log_events(); - auto start_iter = log_start_events.begin(); - auto end_iter = log_end_events.begin(); - while (start_iter != log_start_events.end()) { - int64_t start = start_iter->log_time_us(); - ++start_iter; - rtc::Optional next_start; - if (start_iter != log_start_events.end()) - next_start.emplace(start_iter->log_time_us()); - if (end_iter != log_end_events.end() && - end_iter->log_time_us() <= - next_start.value_or(std::numeric_limits::max())) { - int64_t end = end_iter->log_time_us(); - RTC_DCHECK_LE(start, end); - log_segments_.push_back(std::make_pair(start, end)); - ++end_iter; - } else { - // we're missing an end event. Assume that it occurred just before the - // next start. - log_segments_.push_back( - std::make_pair(start, next_start.value_or(end_time_))); + PacketDirection direction; + uint8_t header[IP_PACKET_SIZE]; + size_t header_length; + size_t total_length; + + uint8_t last_incoming_rtcp_packet[IP_PACKET_SIZE]; + uint8_t last_incoming_rtcp_packet_length = 0; + + // Make a default extension map for streams without configuration information. + // TODO(ivoc): Once configuration of audio streams is stored in the event log, + // this can be removed. Tracking bug: webrtc:6399 + RtpHeaderExtensionMap default_extension_map = GetDefaultHeaderExtensionMap(); + + rtc::Optional last_log_start; + + for (size_t i = 0; i < parsed_log_.GetNumberOfEvents(); i++) { + ParsedRtcEventLog::EventType event_type = parsed_log_.GetEventType(i); + if (event_type != ParsedRtcEventLog::VIDEO_RECEIVER_CONFIG_EVENT && + event_type != ParsedRtcEventLog::VIDEO_SENDER_CONFIG_EVENT && + event_type != ParsedRtcEventLog::AUDIO_RECEIVER_CONFIG_EVENT && + event_type != ParsedRtcEventLog::AUDIO_SENDER_CONFIG_EVENT && + event_type != ParsedRtcEventLog::LOG_START && + event_type != ParsedRtcEventLog::LOG_END) { + uint64_t timestamp = parsed_log_.GetTimestamp(i); + first_timestamp = std::min(first_timestamp, timestamp); + last_timestamp = std::max(last_timestamp, timestamp); } + + switch (parsed_log_.GetEventType(i)) { + case ParsedRtcEventLog::VIDEO_RECEIVER_CONFIG_EVENT: { + rtclog::StreamConfig config = parsed_log_.GetVideoReceiveConfig(i); + StreamId stream(config.remote_ssrc, kIncomingPacket); + video_ssrcs_.insert(stream); + StreamId rtx_stream(config.rtx_ssrc, kIncomingPacket); + video_ssrcs_.insert(rtx_stream); + rtx_ssrcs_.insert(rtx_stream); + break; + } + case ParsedRtcEventLog::VIDEO_SENDER_CONFIG_EVENT: { + std::vector configs = + parsed_log_.GetVideoSendConfig(i); + for (const auto& config : configs) { + StreamId stream(config.local_ssrc, kOutgoingPacket); + video_ssrcs_.insert(stream); + StreamId rtx_stream(config.rtx_ssrc, kOutgoingPacket); + video_ssrcs_.insert(rtx_stream); + rtx_ssrcs_.insert(rtx_stream); + } + break; + } + case ParsedRtcEventLog::AUDIO_RECEIVER_CONFIG_EVENT: { + rtclog::StreamConfig config = parsed_log_.GetAudioReceiveConfig(i); + StreamId stream(config.remote_ssrc, kIncomingPacket); + audio_ssrcs_.insert(stream); + break; + } + case ParsedRtcEventLog::AUDIO_SENDER_CONFIG_EVENT: { + rtclog::StreamConfig config = parsed_log_.GetAudioSendConfig(i); + StreamId stream(config.local_ssrc, kOutgoingPacket); + audio_ssrcs_.insert(stream); + break; + } + case ParsedRtcEventLog::RTP_EVENT: { + RtpHeaderExtensionMap* extension_map = parsed_log_.GetRtpHeader( + i, &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); + } + uint64_t timestamp = parsed_log_.GetTimestamp(i); + StreamId stream(parsed_header.ssrc, direction); + rtp_packets_[stream].push_back(LoggedRtpPacket( + timestamp, parsed_header, header_length, total_length)); + break; + } + case ParsedRtcEventLog::RTCP_EVENT: { + uint8_t packet[IP_PACKET_SIZE]; + parsed_log_.GetRtcpPacket(i, &direction, packet, &total_length); + // 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 (direction == webrtc::kIncomingPacket) { + RTC_CHECK_LE(total_length, IP_PACKET_SIZE); + if (total_length == last_incoming_rtcp_packet_length && + memcmp(last_incoming_rtcp_packet, packet, total_length) == 0) { + continue; + } else { + memcpy(last_incoming_rtcp_packet, packet, total_length); + last_incoming_rtcp_packet_length = 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) { + std::unique_ptr rtcp_packet( + rtc::MakeUnique()); + if (rtcp_packet->Parse(header)) { + uint32_t ssrc = rtcp_packet->sender_ssrc(); + StreamId stream(ssrc, direction); + uint64_t timestamp = parsed_log_.GetTimestamp(i); + rtcp_packets_[stream].push_back(LoggedRtcpPacket( + timestamp, kRtcpTransportFeedback, std::move(rtcp_packet))); + } + } else if (header.type() == rtcp::SenderReport::kPacketType) { + std::unique_ptr rtcp_packet( + rtc::MakeUnique()); + if (rtcp_packet->Parse(header)) { + uint32_t ssrc = rtcp_packet->sender_ssrc(); + StreamId stream(ssrc, direction); + uint64_t timestamp = parsed_log_.GetTimestamp(i); + rtcp_packets_[stream].push_back( + LoggedRtcpPacket(timestamp, kRtcpSr, std::move(rtcp_packet))); + } + } else if (header.type() == rtcp::ReceiverReport::kPacketType) { + std::unique_ptr rtcp_packet( + rtc::MakeUnique()); + if (rtcp_packet->Parse(header)) { + uint32_t ssrc = rtcp_packet->sender_ssrc(); + StreamId stream(ssrc, direction); + uint64_t timestamp = parsed_log_.GetTimestamp(i); + rtcp_packets_[stream].push_back( + LoggedRtcpPacket(timestamp, kRtcpRr, std::move(rtcp_packet))); + } + } else if (header.type() == rtcp::Remb::kPacketType && + header.fmt() == rtcp::Remb::kFeedbackMessageType) { + std::unique_ptr rtcp_packet( + rtc::MakeUnique()); + if (rtcp_packet->Parse(header)) { + uint32_t ssrc = rtcp_packet->sender_ssrc(); + StreamId stream(ssrc, direction); + uint64_t timestamp = parsed_log_.GetTimestamp(i); + rtcp_packets_[stream].push_back(LoggedRtcpPacket( + timestamp, kRtcpRemb, std::move(rtcp_packet))); + } + } + } + break; + } + case ParsedRtcEventLog::LOG_START: { + if (last_log_start) { + // A LOG_END event was missing. Use last_timestamp. + RTC_DCHECK_GE(last_timestamp, *last_log_start); + log_segments_.push_back( + std::make_pair(*last_log_start, last_timestamp)); + } + last_log_start = parsed_log_.GetTimestamp(i); + break; + } + case ParsedRtcEventLog::LOG_END: { + RTC_DCHECK(last_log_start); + log_segments_.push_back( + std::make_pair(*last_log_start, parsed_log_.GetTimestamp(i))); + last_log_start.reset(); + break; + } + case ParsedRtcEventLog::AUDIO_PLAYOUT_EVENT: { + uint32_t this_ssrc; + parsed_log_.GetAudioPlayout(i, &this_ssrc); + audio_playout_events_[this_ssrc].push_back(parsed_log_.GetTimestamp(i)); + break; + } + case ParsedRtcEventLog::LOSS_BASED_BWE_UPDATE: { + LossBasedBweUpdate bwe_update; + bwe_update.timestamp = parsed_log_.GetTimestamp(i); + parsed_log_.GetLossBasedBweUpdate(i, &bwe_update.new_bitrate, + &bwe_update.fraction_loss, + &bwe_update.expected_packets); + bwe_loss_updates_.push_back(bwe_update); + break; + } + case ParsedRtcEventLog::DELAY_BASED_BWE_UPDATE: { + bwe_delay_updates_.push_back(parsed_log_.GetDelayBasedBweUpdate(i)); + break; + } + case ParsedRtcEventLog::AUDIO_NETWORK_ADAPTATION_EVENT: { + AudioNetworkAdaptationEvent ana_event; + ana_event.timestamp = parsed_log_.GetTimestamp(i); + parsed_log_.GetAudioNetworkAdaptation(i, &ana_event.config); + audio_network_adaptation_events_.push_back(ana_event); + break; + } + case ParsedRtcEventLog::BWE_PROBE_CLUSTER_CREATED_EVENT: { + bwe_probe_cluster_created_events_.push_back( + parsed_log_.GetBweProbeClusterCreated(i)); + break; + } + case ParsedRtcEventLog::BWE_PROBE_RESULT_EVENT: { + bwe_probe_result_events_.push_back(parsed_log_.GetBweProbeResult(i)); + break; + } + case ParsedRtcEventLog::ALR_STATE_EVENT: { + 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; + } + } + } + + if (last_timestamp < first_timestamp) { + // No useful events in the log. + first_timestamp = last_timestamp = 0; + } + begin_time_ = first_timestamp; + end_time_ = last_timestamp; + 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_)); } RTC_LOG(LS_INFO) << "Found " << log_segments_.size() << " (LOG_START, LOG_END) segments in log."; @@ -510,7 +678,7 @@ class BitrateObserver : public NetworkChangedObserver, BitrateObserver() : last_bitrate_bps_(0), bitrate_updated_(false) {} void OnNetworkChanged(uint32_t bitrate_bps, - uint8_t fraction_lost, + uint8_t fraction_loss, int64_t rtt_ms, int64_t probing_interval_ms) override { last_bitrate_bps_ = bitrate_bps; @@ -532,90 +700,187 @@ class BitrateObserver : public NetworkChangedObserver, bool bitrate_updated_; }; +bool EventLogAnalyzer::IsRtxSsrc(StreamId stream_id) const { + return rtx_ssrcs_.count(stream_id) == 1; +} + +bool EventLogAnalyzer::IsVideoSsrc(StreamId stream_id) const { + return video_ssrcs_.count(stream_id) == 1; +} + +bool EventLogAnalyzer::IsAudioSsrc(StreamId stream_id) const { + return audio_ssrcs_.count(stream_id) == 1; +} + +std::string EventLogAnalyzer::GetStreamName(StreamId stream_id) const { + std::stringstream name; + if (IsAudioSsrc(stream_id)) { + name << "Audio "; + } else if (IsVideoSsrc(stream_id)) { + name << "Video "; + } else { + name << "Unknown "; + } + if (IsRtxSsrc(stream_id)) + name << "RTX "; + if (stream_id.GetDirection() == kIncomingPacket) { + name << "(In) "; + } else { + name << "(Out) "; + } + name << SsrcToString(stream_id.GetSsrc()); + return name.str(); +} + +// This is much more reliable for outgoing streams than for incoming streams. +rtc::Optional EventLogAnalyzer::EstimateRtpClockFrequency( + const std::vector& packets) const { + RTC_CHECK(packets.size() >= 2); + uint64_t end_time_us = log_segments_.empty() + ? std::numeric_limits::max() + : log_segments_.front().second; + SeqNumUnwrapper unwrapper; + uint64_t first_rtp_timestamp = unwrapper.Unwrap(packets[0].header.timestamp); + uint64_t first_log_timestamp = packets[0].timestamp; + uint64_t last_rtp_timestamp = first_rtp_timestamp; + uint64_t last_log_timestamp = first_log_timestamp; + for (size_t i = 1; i < packets.size(); i++) { + if (packets[i].timestamp > end_time_us) + break; + last_rtp_timestamp = unwrapper.Unwrap(packets[i].header.timestamp); + last_log_timestamp = packets[i].timestamp; + } + if (last_log_timestamp - first_log_timestamp < kNumMicrosecsPerSec) { + RTC_LOG(LS_WARNING) + << "Failed to estimate RTP clock frequency: Stream too short. (" + << packets.size() << " packets, " + << last_log_timestamp - first_log_timestamp << " us)"; + return rtc::nullopt; + } + double duration = + 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}) { + if (std::fabs(estimated_frequency - f) < 0.05 * f) { + return f; + } + } + RTC_LOG(LS_WARNING) << "Failed to estimate RTP clock frequency: Estimate " + << estimated_frequency + << "not close to any stardard RTP frequency."; + return rtc::nullopt; +} + float EventLogAnalyzer::ToCallTime(int64_t timestamp) const { return static_cast(timestamp - begin_time_) / kNumMicrosecsPerSec; } -void EventLogAnalyzer::CreatePacketGraph(PacketDirection direction, +void EventLogAnalyzer::CreatePacketGraph(PacketDirection desired_direction, Plot* plot) { - for (const auto& stream : parsed_log_.rtp_packets_by_ssrc(direction)) { - // Filter on SSRC. - if (!MatchingSsrc(stream.ssrc, desired_ssrc_)) { + for (auto& kv : rtp_packets_) { + StreamId stream_id = kv.first; + const std::vector& packet_stream = kv.second; + // Filter on direction and SSRC. + if (stream_id.GetDirection() != desired_direction || + !MatchingSsrc(stream_id.GetSsrc(), desired_ssrc_)) { continue; } - TimeSeries time_series(GetStreamName(direction, stream.ssrc), - LineStyle::kBar); - auto GetPacketSize = [](const LoggedRtpPacket& packet) { - return rtc::Optional(packet.total_length); - }; - ProcessPoints(GetPacketSize, stream.packet_view, - begin_time_, &time_series); + TimeSeries time_series(GetStreamName(stream_id), LineStyle::kBar); + ProcessPoints( + [](const LoggedRtpPacket& packet) { + return rtc::Optional(packet.total_length); + }, + packet_stream, begin_time_, &time_series); plot->AppendTimeSeries(std::move(time_series)); } plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); plot->SetSuggestedYAxis(0, 1, "Packet size (bytes)", kBottomMargin, kTopMargin); - plot->SetTitle(GetDirectionAsString(direction) + " RTP packets"); + if (desired_direction == webrtc::PacketDirection::kIncomingPacket) { + plot->SetTitle("Incoming RTP packets"); + } else if (desired_direction == webrtc::PacketDirection::kOutgoingPacket) { + plot->SetTitle("Outgoing RTP packets"); + } } -template +template void EventLogAnalyzer::CreateAccumulatedPacketsTimeSeries( + PacketDirection desired_direction, Plot* plot, - const IterableType& packets, - const std::string& label) { - TimeSeries time_series(label, LineStyle::kStep); - for (size_t i = 0; i < packets.size(); i++) { - float x = ToCallTime(packets[i].log_time_us()); - time_series.points.emplace_back(x, i + 1); + const std::map>& packets, + const std::string& label_prefix) { + for (auto& kv : packets) { + StreamId stream_id = kv.first; + const std::vector& packet_stream = kv.second; + // Filter on direction and SSRC. + if (stream_id.GetDirection() != desired_direction || + !MatchingSsrc(stream_id.GetSsrc(), desired_ssrc_)) { + continue; + } + + 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 = ToCallTime(packet_stream[i].timestamp); + time_series.points.emplace_back(x, i + 1); + } + + plot->AppendTimeSeries(std::move(time_series)); } - plot->AppendTimeSeries(std::move(time_series)); } -void EventLogAnalyzer::CreateAccumulatedPacketsGraph(PacketDirection direction, - Plot* plot) { - for (const auto& stream : parsed_log_.rtp_packets_by_ssrc(direction)) { - if (!MatchingSsrc(stream.ssrc, desired_ssrc_)) - continue; - std::string label = - std::string("RTP ") + GetStreamName(direction, stream.ssrc); - CreateAccumulatedPacketsTimeSeries(plot, stream.packet_view, label); - } - std::string label = - std::string("RTCP ") + "(" + GetDirectionAsShortString(direction) + ")"; - if (direction == kIncomingPacket) { - CreateAccumulatedPacketsTimeSeries( - plot, parsed_log_.incoming_rtcp_packets(), label); - } else { - CreateAccumulatedPacketsTimeSeries( - plot, parsed_log_.outgoing_rtcp_packets(), label); - } +void EventLogAnalyzer::CreateAccumulatedPacketsGraph( + PacketDirection desired_direction, + Plot* plot) { + CreateAccumulatedPacketsTimeSeries(desired_direction, plot, rtp_packets_, + "RTP"); + CreateAccumulatedPacketsTimeSeries(desired_direction, plot, rtcp_packets_, + "RTCP"); plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); plot->SetSuggestedYAxis(0, 1, "Received Packets", kBottomMargin, kTopMargin); - plot->SetTitle(std::string("Accumulated ") + GetDirectionAsString(direction) + - " RTP/RTCP packets"); + if (desired_direction == webrtc::PacketDirection::kIncomingPacket) { + plot->SetTitle("Accumulated Incoming RTP/RTCP packets"); + } else if (desired_direction == webrtc::PacketDirection::kOutgoingPacket) { + plot->SetTitle("Accumulated Outgoing RTP/RTCP packets"); + } } // For each SSRC, plot the time between the consecutive playouts. void EventLogAnalyzer::CreatePlayoutGraph(Plot* plot) { - for (const auto& playout_stream : parsed_log_.audio_playout_events()) { - uint32_t ssrc = playout_stream.first; - if (!MatchingSsrc(ssrc, desired_ssrc_)) - continue; - rtc::Optional last_playout; - TimeSeries time_series(SsrcToString(ssrc), LineStyle::kBar); - for (const auto& playout_time : playout_stream.second) { - float x = ToCallTime(playout_time); - // If there were no previous playouts, place the point on the x-axis. - float y = static_cast(playout_time - - last_playout.value_or(playout_time)) / - 1000; - time_series.points.push_back(TimeSeriesPoint(x, y)); - last_playout.emplace(playout_time); + std::map time_series; + std::map last_playout; + + uint32_t ssrc; + + for (size_t i = 0; i < parsed_log_.GetNumberOfEvents(); i++) { + ParsedRtcEventLog::EventType event_type = parsed_log_.GetEventType(i); + if (event_type == ParsedRtcEventLog::AUDIO_PLAYOUT_EVENT) { + parsed_log_.GetAudioPlayout(i, &ssrc); + uint64_t timestamp = parsed_log_.GetTimestamp(i); + if (MatchingSsrc(ssrc, desired_ssrc_)) { + 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. + // Generate a point, but place it on the x-axis. + y = 0; + } + time_series[ssrc].points.push_back(TimeSeriesPoint(x, y)); + last_playout[ssrc] = timestamp; + } } - plot->AppendTimeSeries(std::move(time_series)); + } + + // Set labels and put in graph. + for (auto& kv : time_series) { + kv.second.label = SsrcToString(kv.first); + kv.second.line_style = LineStyle::kBar; + plot->AppendTimeSeries(std::move(kv.second)); } plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); @@ -625,51 +890,59 @@ void EventLogAnalyzer::CreatePlayoutGraph(Plot* plot) { } // For audio SSRCs, plot the audio level. -void EventLogAnalyzer::CreateAudioLevelGraph(PacketDirection direction, - Plot* plot) { - for (const auto& stream : parsed_log_.rtp_packets_by_ssrc(direction)) { - if (!IsAudioSsrc(direction, stream.ssrc)) - continue; - TimeSeries time_series(GetStreamName(direction, stream.ssrc), - LineStyle::kLine); - for (auto& packet : stream.packet_view) { +void EventLogAnalyzer::CreateAudioLevelGraph(Plot* plot) { + std::map time_series; + + for (auto& kv : rtp_packets_) { + StreamId stream_id = kv.first; + const std::vector& packet_stream = kv.second; + // TODO(ivoc): When audio send/receive configs are stored in the event + // log, a check should be added here to only process audio + // streams. Tracking bug: webrtc:6399 + for (auto& packet : packet_stream) { if (packet.header.extension.hasAudioLevel) { - float x = ToCallTime(packet.log_time_us()); + 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); - time_series.points.emplace_back(TimeSeriesPoint(x, y)); + time_series[stream_id].points.emplace_back(TimeSeriesPoint(x, y)); } } - plot->AppendTimeSeries(std::move(time_series)); + } + + for (auto& series : time_series) { + series.second.label = GetStreamName(series.first); + series.second.line_style = LineStyle::kLine; + plot->AppendTimeSeries(std::move(series.second)); } plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); plot->SetYAxis(-127, 0, "Audio level (dBov)", kBottomMargin, kTopMargin); - plot->SetTitle(GetDirectionAsString(direction) + " audio level"); + plot->SetTitle("Audio level"); } // For each SSRC, plot the time between the consecutive playouts. void EventLogAnalyzer::CreateSequenceNumberGraph(Plot* plot) { - for (const auto& stream : parsed_log_.incoming_rtp_packets_by_ssrc()) { - // Filter on SSRC. - if (!MatchingSsrc(stream.ssrc, desired_ssrc_)) { + for (auto& kv : rtp_packets_) { + StreamId stream_id = kv.first; + const std::vector& packet_stream = kv.second; + // Filter on direction and SSRC. + if (stream_id.GetDirection() != kIncomingPacket || + !MatchingSsrc(stream_id.GetSsrc(), desired_ssrc_)) { continue; } - TimeSeries time_series(GetStreamName(kIncomingPacket, stream.ssrc), - LineStyle::kBar); - auto GetSequenceNumberDiff = [](const LoggedRtpPacketIncoming& old_packet, - const LoggedRtpPacketIncoming& new_packet) { - int64_t diff = - WrappingDifference(new_packet.rtp.header.sequenceNumber, - old_packet.rtp.header.sequenceNumber, 1ul << 16); - return diff; - }; - ProcessPairs(GetSequenceNumberDiff, - stream.incoming_packets, - begin_time_, &time_series); + TimeSeries time_series(GetStreamName(stream_id), LineStyle::kBar); + ProcessPairs( + [](const LoggedRtpPacket& old_packet, + const LoggedRtpPacket& new_packet) { + int64_t diff = + WrappingDifference(new_packet.header.sequenceNumber, + old_packet.header.sequenceNumber, 1ul << 16); + return diff; + }, + packet_stream, begin_time_, &time_series); plot->AppendTimeSeries(std::move(time_series)); } @@ -680,47 +953,47 @@ void EventLogAnalyzer::CreateSequenceNumberGraph(Plot* plot) { } void EventLogAnalyzer::CreateIncomingPacketLossGraph(Plot* plot) { - for (const auto& stream : parsed_log_.incoming_rtp_packets_by_ssrc()) { - const std::vector& packets = - stream.incoming_packets; - // Filter on SSRC. - if (!MatchingSsrc(stream.ssrc, desired_ssrc_) || packets.size() == 0) { + for (auto& kv : rtp_packets_) { + StreamId stream_id = kv.first; + const std::vector& packet_stream = kv.second; + // Filter on direction and SSRC. + if (stream_id.GetDirection() != kIncomingPacket || + !MatchingSsrc(stream_id.GetSsrc(), desired_ssrc_) || + packet_stream.size() == 0) { continue; } - TimeSeries time_series(GetStreamName(kIncomingPacket, stream.ssrc), - LineStyle::kLine, PointStyle::kHighlight); - // TODO(terelius): Should the window and step size be read from the class - // instead? - const int64_t kWindowUs = 1000000; - const int64_t kStep = 1000000; + TimeSeries time_series(GetStreamName(stream_id), LineStyle::kLine, + PointStyle::kHighlight); + const uint64_t kWindowUs = 1000000; + const uint64_t kStep = 1000000; SeqNumUnwrapper unwrapper_; SeqNumUnwrapper prior_unwrapper_; size_t window_index_begin = 0; size_t window_index_end = 0; - uint64_t highest_seq_number = - unwrapper_.Unwrap(packets[0].rtp.header.sequenceNumber) - 1; - uint64_t highest_prior_seq_number = - prior_unwrapper_.Unwrap(packets[0].rtp.header.sequenceNumber) - 1; + int64_t highest_seq_number = + unwrapper_.Unwrap(packet_stream[0].header.sequenceNumber) - 1; + int64_t highest_prior_seq_number = + prior_unwrapper_.Unwrap(packet_stream[0].header.sequenceNumber) - 1; - for (int64_t t = begin_time_; t < end_time_ + kStep; t += kStep) { - while (window_index_end < packets.size() && - packets[window_index_end].rtp.log_time_us() < t) { - uint64_t sequence_number = unwrapper_.Unwrap( - packets[window_index_end].rtp.header.sequenceNumber); + for (uint64_t t = begin_time_; t < end_time_ + kStep; t += kStep) { + while (window_index_end < packet_stream.size() && + packet_stream[window_index_end].timestamp < t) { + int64_t sequence_number = unwrapper_.Unwrap( + packet_stream[window_index_end].header.sequenceNumber); highest_seq_number = std::max(highest_seq_number, sequence_number); ++window_index_end; } - while (window_index_begin < packets.size() && - packets[window_index_begin].rtp.log_time_us() < t - kWindowUs) { - uint64_t sequence_number = prior_unwrapper_.Unwrap( - packets[window_index_begin].rtp.header.sequenceNumber); + while (window_index_begin < packet_stream.size() && + packet_stream[window_index_begin].timestamp < t - kWindowUs) { + int64_t sequence_number = prior_unwrapper_.Unwrap( + packet_stream[window_index_begin].header.sequenceNumber); highest_prior_seq_number = std::max(highest_prior_seq_number, sequence_number); ++window_index_begin; } float x = ToCallTime(t); - uint64_t expected_packets = highest_seq_number - highest_prior_seq_number; + 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; int64_t lost_packets = expected_packets - received_packets; @@ -738,28 +1011,28 @@ void EventLogAnalyzer::CreateIncomingPacketLossGraph(Plot* plot) { } void EventLogAnalyzer::CreateIncomingDelayDeltaGraph(Plot* plot) { - for (const auto& stream : parsed_log_.rtp_packets_by_ssrc(kIncomingPacket)) { - // Filter on SSRC. - if (!MatchingSsrc(stream.ssrc, desired_ssrc_) || - IsAudioSsrc(kIncomingPacket, stream.ssrc) || - !IsVideoSsrc(kIncomingPacket, stream.ssrc) || - IsRtxSsrc(kIncomingPacket, stream.ssrc)) { + for (auto& kv : rtp_packets_) { + StreamId stream_id = kv.first; + const std::vector& packet_stream = kv.second; + // Filter on direction and SSRC. + if (stream_id.GetDirection() != kIncomingPacket || + !MatchingSsrc(stream_id.GetSsrc(), desired_ssrc_) || + IsAudioSsrc(stream_id) || !IsVideoSsrc(stream_id) || + IsRtxSsrc(stream_id)) { continue; } - TimeSeries capture_time_data( - GetStreamName(kIncomingPacket, stream.ssrc) + " capture-time", - LineStyle::kBar); + TimeSeries capture_time_data(GetStreamName(stream_id) + " capture-time", + LineStyle::kBar); ProcessPairs(NetworkDelayDiff_CaptureTime, - stream.packet_view, begin_time_, + packet_stream, begin_time_, &capture_time_data); plot->AppendTimeSeries(std::move(capture_time_data)); - TimeSeries send_time_data( - GetStreamName(kIncomingPacket, stream.ssrc) + " abs-send-time", - LineStyle::kBar); + TimeSeries send_time_data(GetStreamName(stream_id) + " abs-send-time", + LineStyle::kBar); ProcessPairs(NetworkDelayDiff_AbsSendTime, - stream.packet_view, begin_time_, + packet_stream, begin_time_, &send_time_data); plot->AppendTimeSeries(std::move(send_time_data)); } @@ -771,28 +1044,28 @@ void EventLogAnalyzer::CreateIncomingDelayDeltaGraph(Plot* plot) { } void EventLogAnalyzer::CreateIncomingDelayGraph(Plot* plot) { - for (const auto& stream : parsed_log_.rtp_packets_by_ssrc(kIncomingPacket)) { - // Filter on SSRC. - if (!MatchingSsrc(stream.ssrc, desired_ssrc_) || - IsAudioSsrc(kIncomingPacket, stream.ssrc) || - !IsVideoSsrc(kIncomingPacket, stream.ssrc) || - IsRtxSsrc(kIncomingPacket, stream.ssrc)) { + for (auto& kv : rtp_packets_) { + StreamId stream_id = kv.first; + const std::vector& packet_stream = kv.second; + // Filter on direction and SSRC. + if (stream_id.GetDirection() != kIncomingPacket || + !MatchingSsrc(stream_id.GetSsrc(), desired_ssrc_) || + IsAudioSsrc(stream_id) || !IsVideoSsrc(stream_id) || + IsRtxSsrc(stream_id)) { continue; } - TimeSeries capture_time_data( - GetStreamName(kIncomingPacket, stream.ssrc) + " capture-time", - LineStyle::kLine); + TimeSeries capture_time_data(GetStreamName(stream_id) + " capture-time", + LineStyle::kLine); AccumulatePairs(NetworkDelayDiff_CaptureTime, - stream.packet_view, begin_time_, + packet_stream, begin_time_, &capture_time_data); plot->AppendTimeSeries(std::move(capture_time_data)); - TimeSeries send_time_data( - GetStreamName(kIncomingPacket, stream.ssrc) + " abs-send-time", - LineStyle::kLine); + TimeSeries send_time_data(GetStreamName(stream_id) + " abs-send-time", + LineStyle::kLine); AccumulatePairs(NetworkDelayDiff_AbsSendTime, - stream.packet_view, begin_time_, + packet_stream, begin_time_, &send_time_data); plot->AppendTimeSeries(std::move(send_time_data)); } @@ -807,9 +1080,9 @@ void EventLogAnalyzer::CreateIncomingDelayGraph(Plot* plot) { void EventLogAnalyzer::CreateFractionLossGraph(Plot* plot) { TimeSeries time_series("Fraction lost", LineStyle::kLine, PointStyle::kHighlight); - for (auto& bwe_update : parsed_log_.bwe_loss_updates()) { - float x = ToCallTime(bwe_update.log_time_us()); - float y = static_cast(bwe_update.fraction_lost) / 255 * 100; + for (auto& bwe_update : bwe_loss_updates_) { + float x = ToCallTime(bwe_update.timestamp); + float y = static_cast(bwe_update.fraction_loss) / 255 * 100; time_series.points.emplace_back(x, y); } @@ -821,82 +1094,51 @@ void EventLogAnalyzer::CreateFractionLossGraph(Plot* plot) { } // Plot the total bandwidth used by all RTP streams. -void EventLogAnalyzer::CreateTotalIncomingBitrateGraph(Plot* plot) { - // TODO(terelius): This could be provided by the parser. - std::multimap packets_in_order; - for (const auto& stream : parsed_log_.incoming_rtp_packets_by_ssrc()) { - for (const LoggedRtpPacketIncoming& packet : stream.incoming_packets) - packets_in_order.insert( - std::make_pair(packet.rtp.log_time_us(), packet.rtp.total_length)); +void EventLogAnalyzer::CreateTotalBitrateGraph( + PacketDirection desired_direction, + Plot* plot, + bool show_detector_state, + bool show_alr_state) { + struct TimestampSize { + TimestampSize(uint64_t t, size_t s) : timestamp(t), size(s) {} + uint64_t timestamp; + size_t size; + }; + std::vector packets; + + PacketDirection direction; + size_t total_length; + + // Extract timestamps and sizes for the relevant packets. + for (size_t i = 0; i < parsed_log_.GetNumberOfEvents(); i++) { + ParsedRtcEventLog::EventType event_type = parsed_log_.GetEventType(i); + if (event_type == ParsedRtcEventLog::RTP_EVENT) { + parsed_log_.GetRtpHeader(i, &direction, nullptr, nullptr, &total_length, + nullptr); + if (direction == desired_direction) { + uint64_t timestamp = parsed_log_.GetTimestamp(i); + packets.push_back(TimestampSize(timestamp, total_length)); + } + } } - auto window_begin = packets_in_order.begin(); - auto window_end = packets_in_order.begin(); + size_t window_index_begin = 0; + size_t window_index_end = 0; size_t bytes_in_window = 0; // Calculate a moving average of the bitrate and store in a TimeSeries. TimeSeries bitrate_series("Bitrate", LineStyle::kLine); - for (int64_t time = begin_time_; time < end_time_ + step_; time += step_) { - while (window_end != packets_in_order.end() && window_end->first < time) { - bytes_in_window += window_end->second; - ++window_end; + for (uint64_t time = begin_time_; time < end_time_ + step_; time += step_) { + while (window_index_end < packets.size() && + packets[window_index_end].timestamp < time) { + bytes_in_window += packets[window_index_end].size; + ++window_index_end; } - while (window_begin != packets_in_order.end() && - window_begin->first < time - window_duration_) { - RTC_DCHECK_LE(window_begin->second, bytes_in_window); - bytes_in_window -= window_begin->second; - ++window_begin; - } - float window_duration_in_seconds = - 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); - } - plot->AppendTimeSeries(std::move(bitrate_series)); - - // Overlay the outgoing REMB over incoming bitrate. - TimeSeries remb_series("Remb", LineStyle::kStep); - for (const auto& rtcp : parsed_log_.rembs(kOutgoingPacket)) { - float x = ToCallTime(rtcp.log_time_us()); - float y = static_cast(rtcp.remb.bitrate_bps()) / 1000; - remb_series.points.emplace_back(x, y); - } - plot->AppendTimeSeriesIfNotEmpty(std::move(remb_series)); - - plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); - plot->SetSuggestedYAxis(0, 1, "Bitrate (kbps)", kBottomMargin, kTopMargin); - plot->SetTitle("Incoming RTP bitrate"); -} - -// Plot the total bandwidth used by all RTP streams. -void EventLogAnalyzer::CreateTotalOutgoingBitrateGraph(Plot* plot, - bool show_detector_state, - bool show_alr_state) { - // TODO(terelius): This could be provided by the parser. - std::multimap packets_in_order; - for (const auto& stream : parsed_log_.outgoing_rtp_packets_by_ssrc()) { - for (const LoggedRtpPacketOutgoing& packet : stream.outgoing_packets) - packets_in_order.insert( - std::make_pair(packet.rtp.log_time_us(), packet.rtp.total_length)); - } - - auto window_begin = packets_in_order.begin(); - auto window_end = packets_in_order.begin(); - size_t bytes_in_window = 0; - - // Calculate a moving average of the bitrate and store in a TimeSeries. - TimeSeries bitrate_series("Bitrate", LineStyle::kLine); - for (int64_t time = begin_time_; time < end_time_ + step_; time += step_) { - while (window_end != packets_in_order.end() && window_end->first < time) { - bytes_in_window += window_end->second; - ++window_end; - } - while (window_begin != packets_in_order.end() && - window_begin->first < time - window_duration_) { - RTC_DCHECK_LE(window_begin->second, bytes_in_window); - bytes_in_window -= window_begin->second; - ++window_begin; + while (window_index_begin < packets.size() && + packets[window_index_begin].timestamp < time - window_duration_) { + RTC_DCHECK_LE(packets[window_index_begin].size, bytes_in_window); + bytes_in_window -= packets[window_index_begin].size; + ++window_index_begin; } float window_duration_in_seconds = static_cast(window_duration_) / kNumMicrosecsPerSec; @@ -907,161 +1149,195 @@ void EventLogAnalyzer::CreateTotalOutgoingBitrateGraph(Plot* plot, plot->AppendTimeSeries(std::move(bitrate_series)); // Overlay the send-side bandwidth estimate over the outgoing bitrate. - TimeSeries loss_series("Loss-based estimate", LineStyle::kStep); - for (auto& loss_update : parsed_log_.bwe_loss_updates()) { - float x = ToCallTime(loss_update.log_time_us()); - float y = static_cast(loss_update.bitrate_bps) / 1000; - loss_series.points.emplace_back(x, y); - } + if (desired_direction == kOutgoingPacket) { + TimeSeries loss_series("Loss-based estimate", LineStyle::kStep); + for (auto& loss_update : bwe_loss_updates_) { + float x = ToCallTime(loss_update.timestamp); + float y = static_cast(loss_update.new_bitrate) / 1000; + loss_series.points.emplace_back(x, y); + } - TimeSeries delay_series("Delay-based estimate", LineStyle::kStep); - IntervalSeries overusing_series("Overusing", "#ff8e82", - IntervalSeries::kHorizontal); - IntervalSeries underusing_series("Underusing", "#5092fc", - IntervalSeries::kHorizontal); - IntervalSeries normal_series("Normal", "#c4ffc4", - IntervalSeries::kHorizontal); - IntervalSeries* last_series = &normal_series; - double last_detector_switch = 0.0; + TimeSeries delay_series("Delay-based estimate", LineStyle::kStep); + IntervalSeries overusing_series("Overusing", "#ff8e82", + IntervalSeries::kHorizontal); + IntervalSeries underusing_series("Underusing", "#5092fc", + IntervalSeries::kHorizontal); + IntervalSeries normal_series("Normal", "#c4ffc4", + IntervalSeries::kHorizontal); + IntervalSeries* last_series = &normal_series; + double last_detector_switch = 0.0; - BandwidthUsage last_detector_state = BandwidthUsage::kBwNormal; + BandwidthUsage last_detector_state = BandwidthUsage::kBwNormal; - for (auto& delay_update : parsed_log_.bwe_delay_updates()) { - float x = ToCallTime(delay_update.log_time_us()); - float y = static_cast(delay_update.bitrate_bps) / 1000; + for (auto& delay_update : bwe_delay_updates_) { + float x = ToCallTime(delay_update.timestamp); + float y = static_cast(delay_update.bitrate_bps) / 1000; - if (last_detector_state != delay_update.detector_state) { - last_series->intervals.emplace_back(last_detector_switch, x); - last_detector_state = delay_update.detector_state; - last_detector_switch = x; + if (last_detector_state != delay_update.detector_state) { + last_series->intervals.emplace_back(last_detector_switch, x); + last_detector_state = delay_update.detector_state; + last_detector_switch = x; - switch (delay_update.detector_state) { - case BandwidthUsage::kBwNormal: - last_series = &normal_series; - break; - case BandwidthUsage::kBwUnderusing: - last_series = &underusing_series; - break; - case BandwidthUsage::kBwOverusing: - last_series = &overusing_series; - break; - case BandwidthUsage::kLast: - RTC_NOTREACHED(); + switch (delay_update.detector_state) { + case BandwidthUsage::kBwNormal: + last_series = &normal_series; + break; + case BandwidthUsage::kBwUnderusing: + last_series = &underusing_series; + break; + case BandwidthUsage::kBwOverusing: + last_series = &overusing_series; + break; + case BandwidthUsage::kLast: + RTC_NOTREACHED(); + } + } + + delay_series.points.emplace_back(x, y); + } + + RTC_CHECK(last_series); + last_series->intervals.emplace_back(last_detector_switch, end_time_); + + TimeSeries created_series("Probe cluster created.", LineStyle::kNone, + PointStyle::kHighlight); + for (auto& cluster : bwe_probe_cluster_created_events_) { + float x = ToCallTime(cluster.timestamp); + float y = static_cast(cluster.bitrate_bps) / 1000; + created_series.points.emplace_back(x, y); + } + + TimeSeries result_series("Probing results.", LineStyle::kNone, + PointStyle::kHighlight); + for (auto& result : bwe_probe_result_events_) { + if (result.bitrate_bps) { + float x = ToCallTime(result.timestamp); + float y = static_cast(*result.bitrate_bps) / 1000; + result_series.points.emplace_back(x, y); } } - delay_series.points.emplace_back(x, y); - } - - RTC_CHECK(last_series); - last_series->intervals.emplace_back(last_detector_switch, end_time_); - - TimeSeries created_series("Probe cluster created.", LineStyle::kNone, - PointStyle::kHighlight); - for (auto& cluster : parsed_log_.bwe_probe_cluster_created_events()) { - float x = ToCallTime(cluster.log_time_us()); - float y = static_cast(cluster.bitrate_bps) / 1000; - created_series.points.emplace_back(x, y); - } - - TimeSeries result_series("Probing results.", LineStyle::kNone, - PointStyle::kHighlight); - for (auto& result : parsed_log_.bwe_probe_result_events()) { - if (result.bitrate_bps) { - float x = ToCallTime(result.log_time_us()); - float y = static_cast(*result.bitrate_bps) / 1000; - result_series.points.emplace_back(x, y); + IntervalSeries alr_state("ALR", "#555555", IntervalSeries::kHorizontal); + bool previously_in_alr = false; + int64_t alr_start = 0; + for (auto& alr : alr_state_events_) { + float y = ToCallTime(alr.timestamp); + if (!previously_in_alr && alr.in_alr) { + alr_start = alr.timestamp; + previously_in_alr = true; + } else if (previously_in_alr && !alr.in_alr) { + float x = ToCallTime(alr_start); + alr_state.intervals.emplace_back(x, y); + previously_in_alr = false; + } } - } - IntervalSeries alr_state("ALR", "#555555", IntervalSeries::kHorizontal); - bool previously_in_alr = false; - int64_t alr_start = 0; - for (auto& alr : parsed_log_.alr_state_events()) { - float y = ToCallTime(alr.log_time_us()); - if (!previously_in_alr && alr.in_alr) { - alr_start = alr.log_time_us(); - previously_in_alr = true; - } else if (previously_in_alr && !alr.in_alr) { + if (previously_in_alr) { float x = ToCallTime(alr_start); + float y = ToCallTime(end_time_); alr_state.intervals.emplace_back(x, y); - previously_in_alr = false; + } + + if (show_detector_state) { + plot->AppendIntervalSeries(std::move(overusing_series)); + plot->AppendIntervalSeries(std::move(underusing_series)); + plot->AppendIntervalSeries(std::move(normal_series)); + } + + if (show_alr_state) { + plot->AppendIntervalSeries(std::move(alr_state)); + } + plot->AppendTimeSeries(std::move(loss_series)); + plot->AppendTimeSeries(std::move(delay_series)); + plot->AppendTimeSeries(std::move(created_series)); + plot->AppendTimeSeries(std::move(result_series)); + } + + // Overlay the incoming REMB over the outgoing bitrate + // and outgoing REMB over incoming bitrate. + PacketDirection remb_direction = + desired_direction == kOutgoingPacket ? kIncomingPacket : kOutgoingPacket; + TimeSeries remb_series("Remb", LineStyle::kStep); + std::multimap remb_packets; + for (const auto& kv : rtcp_packets_) { + if (kv.first.GetDirection() == remb_direction) { + for (const LoggedRtcpPacket& rtcp_packet : kv.second) { + if (rtcp_packet.type == kRtcpRemb) { + remb_packets.insert( + std::make_pair(rtcp_packet.timestamp, &rtcp_packet)); + } + } } } - if (previously_in_alr) { - float x = ToCallTime(alr_start); - float y = ToCallTime(end_time_); - alr_state.intervals.emplace_back(x, y); - } - - if (show_detector_state) { - plot->AppendIntervalSeries(std::move(overusing_series)); - plot->AppendIntervalSeries(std::move(underusing_series)); - plot->AppendIntervalSeries(std::move(normal_series)); - } - - if (show_alr_state) { - plot->AppendIntervalSeries(std::move(alr_state)); - } - plot->AppendTimeSeries(std::move(loss_series)); - plot->AppendTimeSeries(std::move(delay_series)); - plot->AppendTimeSeries(std::move(created_series)); - plot->AppendTimeSeries(std::move(result_series)); - - // Overlay the incoming REMB over the outgoing bitrate. - TimeSeries remb_series("Remb", LineStyle::kStep); - for (const auto& rtcp : parsed_log_.rembs(kIncomingPacket)) { - float x = ToCallTime(rtcp.log_time_us()); - float y = static_cast(rtcp.remb.bitrate_bps()) / 1000; + for (const auto& kv : remb_packets) { + const LoggedRtcpPacket* const rtcp = kv.second; + const rtcp::Remb* const remb = static_cast(rtcp->packet.get()); + float x = ToCallTime(rtcp->timestamp); + float y = static_cast(remb->bitrate_bps()) / 1000; remb_series.points.emplace_back(x, y); } plot->AppendTimeSeriesIfNotEmpty(std::move(remb_series)); plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); plot->SetSuggestedYAxis(0, 1, "Bitrate (kbps)", kBottomMargin, kTopMargin); - plot->SetTitle("Outgoing RTP bitrate"); + if (desired_direction == webrtc::PacketDirection::kIncomingPacket) { + plot->SetTitle("Incoming RTP bitrate"); + } else if (desired_direction == webrtc::PacketDirection::kOutgoingPacket) { + plot->SetTitle("Outgoing RTP bitrate"); + } } // For each SSRC, plot the bandwidth used by that stream. -void EventLogAnalyzer::CreateStreamBitrateGraph(PacketDirection direction, - Plot* plot) { - for (const auto& stream : parsed_log_.rtp_packets_by_ssrc(direction)) { - // Filter on SSRC. - if (!MatchingSsrc(stream.ssrc, desired_ssrc_)) { +void EventLogAnalyzer::CreateStreamBitrateGraph( + PacketDirection desired_direction, + Plot* plot) { + for (auto& kv : rtp_packets_) { + StreamId stream_id = kv.first; + const std::vector& packet_stream = kv.second; + // Filter on direction and SSRC. + if (stream_id.GetDirection() != desired_direction || + !MatchingSsrc(stream_id.GetSsrc(), desired_ssrc_)) { continue; } - TimeSeries time_series(GetStreamName(direction, stream.ssrc), - LineStyle::kLine); - auto GetPacketSizeKilobits = [](const LoggedRtpPacket& packet) { - return packet.total_length * 8.0 / 1000.0; - }; + TimeSeries time_series(GetStreamName(stream_id), LineStyle::kLine); MovingAverage( - GetPacketSizeKilobits, stream.packet_view, begin_time_, end_time_, - window_duration_, step_, &time_series); + [](const LoggedRtpPacket& packet) { + return packet.total_length * 8.0 / 1000.0; + }, + packet_stream, begin_time_, end_time_, window_duration_, step_, + &time_series); plot->AppendTimeSeries(std::move(time_series)); } plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); plot->SetSuggestedYAxis(0, 1, "Bitrate (kbps)", kBottomMargin, kTopMargin); - plot->SetTitle(GetDirectionAsString(direction) + " bitrate per stream"); + if (desired_direction == webrtc::PacketDirection::kIncomingPacket) { + plot->SetTitle("Incoming bitrate per stream"); + } else if (desired_direction == webrtc::PacketDirection::kOutgoingPacket) { + plot->SetTitle("Outgoing bitrate per stream"); + } } void EventLogAnalyzer::CreateSendSideBweSimulationGraph(Plot* plot) { - using RtpPacketType = LoggedRtpPacketOutgoing; - using TransportFeedbackType = LoggedRtcpPacketTransportFeedback; + std::multimap outgoing_rtp; + std::multimap incoming_rtcp; - // TODO(terelius): This could be provided by the parser. - std::multimap outgoing_rtp; - for (const auto& stream : parsed_log_.outgoing_rtp_packets_by_ssrc()) { - for (const RtpPacketType& rtp_packet : stream.outgoing_packets) - outgoing_rtp.insert( - std::make_pair(rtp_packet.rtp.log_time_us(), &rtp_packet)); + for (const auto& kv : rtp_packets_) { + if (kv.first.GetDirection() == PacketDirection::kOutgoingPacket) { + for (const LoggedRtpPacket& rtp_packet : kv.second) + outgoing_rtp.insert(std::make_pair(rtp_packet.timestamp, &rtp_packet)); + } } - const std::vector& incoming_rtcp = - parsed_log_.transport_feedbacks(kIncomingPacket); + for (const auto& kv : rtcp_packets_) { + if (kv.first.GetDirection() == PacketDirection::kIncomingPacket) { + for (const LoggedRtcpPacket& rtcp_packet : kv.second) + incoming_rtcp.insert( + std::make_pair(rtcp_packet.timestamp, &rtcp_packet)); + } + } SimulatedClock clock(0); BitrateObserver observer; @@ -1091,7 +1367,7 @@ void EventLogAnalyzer::CreateSendSideBweSimulationGraph(Plot* plot) { auto NextRtcpTime = [&]() { if (rtcp_iterator != incoming_rtcp.end()) - return static_cast(rtcp_iterator->log_time_us()); + return static_cast(rtcp_iterator->first); return std::numeric_limits::max(); }; @@ -1122,38 +1398,41 @@ void EventLogAnalyzer::CreateSendSideBweSimulationGraph(Plot* plot) { clock.AdvanceTimeMicroseconds(time_us - clock.TimeInMicroseconds()); if (clock.TimeInMicroseconds() >= NextRtcpTime()) { RTC_DCHECK_EQ(clock.TimeInMicroseconds(), NextRtcpTime()); - cc.OnTransportFeedback(rtcp_iterator->transport_feedback); - std::vector feedback = cc.GetTransportFeedbackVector(); - SortPacketFeedbackVector(&feedback); - rtc::Optional bitrate_bps; - if (!feedback.empty()) { + const LoggedRtcpPacket& rtcp = *rtcp_iterator->second; + if (rtcp.type == kRtcpTransportFeedback) { + cc.OnTransportFeedback( + *static_cast(rtcp.packet.get())); + std::vector feedback = cc.GetTransportFeedbackVector(); + SortPacketFeedbackVector(&feedback); + rtc::Optional bitrate_bps; + if (!feedback.empty()) { #if !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE) - acknowledged_bitrate_estimator.IncomingPacketFeedbackVector(feedback); + acknowledged_bitrate_estimator.IncomingPacketFeedbackVector(feedback); +#endif // !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE) + for (const PacketFeedback& packet : feedback) + acked_bitrate.Update(packet.payload_size, packet.arrival_time_ms); + bitrate_bps = acked_bitrate.Rate(feedback.back().arrival_time_ms); + } + 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) + y = acknowledged_bitrate_estimator.bitrate_bps().value_or(0) / 1000; + acked_estimate_time_series.points.emplace_back(x, y); #endif // !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE) - for (const PacketFeedback& packet : feedback) - acked_bitrate.Update(packet.payload_size, packet.arrival_time_ms); - bitrate_bps = acked_bitrate.Rate(feedback.back().arrival_time_ms); } - 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) - y = acknowledged_bitrate_estimator.bitrate_bps().value_or(0) / 1000; - acked_estimate_time_series.points.emplace_back(x, y); -#endif // !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE) ++rtcp_iterator; } if (clock.TimeInMicroseconds() >= NextRtpTime()) { RTC_DCHECK_EQ(clock.TimeInMicroseconds(), NextRtpTime()); - const RtpPacketType& rtp_packet = *rtp_iterator->second; - if (rtp_packet.rtp.header.extension.hasTransportSequenceNumber) { - RTC_DCHECK(rtp_packet.rtp.header.extension.hasTransportSequenceNumber); - cc.AddPacket(rtp_packet.rtp.header.ssrc, - rtp_packet.rtp.header.extension.transportSequenceNumber, - rtp_packet.rtp.total_length, PacedPacketInfo()); + const LoggedRtpPacket& rtp = *rtp_iterator->second; + if (rtp.header.extension.hasTransportSequenceNumber) { + RTC_DCHECK(rtp.header.extension.hasTransportSequenceNumber); + cc.AddPacket(rtp.header.ssrc, + rtp.header.extension.transportSequenceNumber, + rtp.total_length, PacedPacketInfo()); rtc::SentPacket sent_packet( - rtp_packet.rtp.header.extension.transportSequenceNumber, - rtp_packet.rtp.log_time_us() / 1000); + rtp.header.extension.transportSequenceNumber, rtp.timestamp / 1000); cc.OnSentPacket(sent_packet); } ++rtp_iterator; @@ -1182,7 +1461,6 @@ void EventLogAnalyzer::CreateSendSideBweSimulationGraph(Plot* plot) { } void EventLogAnalyzer::CreateReceiveSideBweSimulationGraph(Plot* plot) { - using RtpPacketType = LoggedRtpPacketIncoming; class RembInterceptingPacketRouter : public PacketRouter { public: void OnReceiveBitrateChanged(const std::vector& ssrcs, @@ -1203,19 +1481,19 @@ void EventLogAnalyzer::CreateReceiveSideBweSimulationGraph(Plot* plot) { bool bitrate_updated_; }; - std::multimap incoming_rtp; + std::multimap incoming_rtp; - for (const auto& stream : parsed_log_.incoming_rtp_packets_by_ssrc()) { - if (IsVideoSsrc(kIncomingPacket, stream.ssrc)) { - for (const auto& rtp_packet : stream.incoming_packets) - incoming_rtp.insert( - std::make_pair(rtp_packet.rtp.log_time_us(), &rtp_packet)); + for (const auto& kv : rtp_packets_) { + if (kv.first.GetDirection() == PacketDirection::kIncomingPacket && + IsVideoSsrc(kv.first)) { + for (const LoggedRtpPacket& rtp_packet : kv.second) + incoming_rtp.insert(std::make_pair(rtp_packet.timestamp, &rtp_packet)); } } SimulatedClock clock(0); RembInterceptingPacketRouter packet_router; - // TODO(terelius): The PacketRouter is used as the RemoteBitrateObserver. + // TODO(terelius): The PacketRrouter is the used as the RemoteBitrateObserver. // Is this intentional? ReceiveSideCongestionController rscc(&clock, &packet_router); // TODO(holmer): Log the call config and use that here instead. @@ -1229,12 +1507,12 @@ void EventLogAnalyzer::CreateReceiveSideBweSimulationGraph(Plot* plot) { RateStatistics acked_bitrate(250, 8000); int64_t last_update_us = 0; for (const auto& kv : incoming_rtp) { - const RtpPacketType& packet = *kv.second; - int64_t arrival_time_ms = packet.rtp.log_time_us() / 1000; - size_t payload = packet.rtp.total_length; /*Should subtract header?*/ - clock.AdvanceTimeMicroseconds(packet.rtp.log_time_us() - + const LoggedRtpPacket& packet = *kv.second; + int64_t arrival_time_ms = packet.timestamp / 1000; + size_t payload = packet.total_length; /*Should subtract header?*/ + clock.AdvanceTimeMicroseconds(packet.timestamp - clock.TimeInMicroseconds()); - rscc.OnReceivedPacket(arrival_time_ms, payload, packet.rtp.header); + rscc.OnReceivedPacket(arrival_time_ms, payload, packet.header); acked_bitrate.Update(payload, arrival_time_ms); rtc::Optional bitrate_bps = acked_bitrate.Rate(arrival_time_ms); if (bitrate_bps) { @@ -1260,19 +1538,23 @@ void EventLogAnalyzer::CreateReceiveSideBweSimulationGraph(Plot* plot) { } void EventLogAnalyzer::CreateNetworkDelayFeedbackGraph(Plot* plot) { - using RtpPacketType = LoggedRtpPacketOutgoing; - using TransportFeedbackType = LoggedRtcpPacketTransportFeedback; + std::multimap outgoing_rtp; + std::multimap incoming_rtcp; - // TODO(terelius): This could be provided by the parser. - std::multimap outgoing_rtp; - for (const auto& stream : parsed_log_.outgoing_rtp_packets_by_ssrc()) { - for (const RtpPacketType& rtp_packet : stream.outgoing_packets) - outgoing_rtp.insert( - std::make_pair(rtp_packet.rtp.log_time_us(), &rtp_packet)); + for (const auto& kv : rtp_packets_) { + if (kv.first.GetDirection() == PacketDirection::kOutgoingPacket) { + for (const LoggedRtpPacket& rtp_packet : kv.second) + outgoing_rtp.insert(std::make_pair(rtp_packet.timestamp, &rtp_packet)); + } } - const std::vector& incoming_rtcp = - parsed_log_.transport_feedbacks(kIncomingPacket); + for (const auto& kv : rtcp_packets_) { + if (kv.first.GetDirection() == PacketDirection::kIncomingPacket) { + for (const LoggedRtcpPacket& rtcp_packet : kv.second) + incoming_rtcp.insert( + std::make_pair(rtcp_packet.timestamp, &rtcp_packet)); + } + } SimulatedClock clock(0); TransportFeedbackAdapter feedback_adapter(&clock); @@ -1294,7 +1576,7 @@ void EventLogAnalyzer::CreateNetworkDelayFeedbackGraph(Plot* plot) { auto NextRtcpTime = [&]() { if (rtcp_iterator != incoming_rtcp.end()) - return static_cast(rtcp_iterator->log_time_us()); + return static_cast(rtcp_iterator->first); return std::numeric_limits::max(); }; @@ -1304,34 +1586,37 @@ void EventLogAnalyzer::CreateNetworkDelayFeedbackGraph(Plot* plot) { clock.AdvanceTimeMicroseconds(time_us - clock.TimeInMicroseconds()); if (clock.TimeInMicroseconds() >= NextRtcpTime()) { RTC_DCHECK_EQ(clock.TimeInMicroseconds(), NextRtcpTime()); - feedback_adapter.OnTransportFeedback(rtcp_iterator->transport_feedback); - std::vector feedback = - feedback_adapter.GetTransportFeedbackVector(); - SortPacketFeedbackVector(&feedback); - for (const PacketFeedback& packet : feedback) { - float x = ToCallTime(clock.TimeInMicroseconds()); - if (packet.send_time_ms == PacketFeedback::kNoSendTime) { - late_feedback_series.points.emplace_back(x, prev_y); - continue; + const LoggedRtcpPacket& rtcp = *rtcp_iterator->second; + if (rtcp.type == kRtcpTransportFeedback) { + feedback_adapter.OnTransportFeedback( + *static_cast(rtcp.packet.get())); + std::vector feedback = + feedback_adapter.GetTransportFeedbackVector(); + SortPacketFeedbackVector(&feedback); + for (const PacketFeedback& packet : feedback) { + float x = ToCallTime(clock.TimeInMicroseconds()); + if (packet.send_time_ms == PacketFeedback::kNoSendTime) { + late_feedback_series.points.emplace_back(x, prev_y); + continue; + } + int64_t y = packet.arrival_time_ms - packet.send_time_ms; + prev_y = y; + estimated_base_delay_ms = std::min(y, estimated_base_delay_ms); + time_series.points.emplace_back(x, y); } - int64_t y = packet.arrival_time_ms - packet.send_time_ms; - prev_y = y; - estimated_base_delay_ms = std::min(y, estimated_base_delay_ms); - time_series.points.emplace_back(x, y); } ++rtcp_iterator; } if (clock.TimeInMicroseconds() >= NextRtpTime()) { RTC_DCHECK_EQ(clock.TimeInMicroseconds(), NextRtpTime()); - const RtpPacketType& rtp_packet = *rtp_iterator->second; - if (rtp_packet.rtp.header.extension.hasTransportSequenceNumber) { - feedback_adapter.AddPacket( - rtp_packet.rtp.header.ssrc, - rtp_packet.rtp.header.extension.transportSequenceNumber, - rtp_packet.rtp.total_length, PacedPacketInfo()); + const LoggedRtpPacket& rtp = *rtp_iterator->second; + if (rtp.header.extension.hasTransportSequenceNumber) { + RTC_DCHECK(rtp.header.extension.hasTransportSequenceNumber); + feedback_adapter.AddPacket(rtp.header.ssrc, + rtp.header.extension.transportSequenceNumber, + rtp.total_length, PacedPacketInfo()); feedback_adapter.OnSentPacket( - rtp_packet.rtp.header.extension.transportSequenceNumber, - rtp_packet.rtp.log_time_us() / 1000); + rtp.header.extension.transportSequenceNumber, rtp.timestamp / 1000); } ++rtp_iterator; } @@ -1352,10 +1637,40 @@ void EventLogAnalyzer::CreateNetworkDelayFeedbackGraph(Plot* plot) { plot->SetTitle("Network Delay Change."); } +std::vector> EventLogAnalyzer::GetFrameTimestamps() + const { + std::vector> timestamps; + size_t largest_stream_size = 0; + const std::vector* largest_video_stream = nullptr; + // Find the incoming video stream with the most number of packets that is + // not rtx. + for (const auto& kv : rtp_packets_) { + if (kv.first.GetDirection() == kIncomingPacket && + video_ssrcs_.find(kv.first) != video_ssrcs_.end() && + rtx_ssrcs_.find(kv.first) == rtx_ssrcs_.end() && + kv.second.size() > largest_stream_size) { + largest_stream_size = kv.second.size(); + largest_video_stream = &kv.second; + } + } + if (largest_video_stream == nullptr) { + for (auto& packet : *largest_video_stream) { + if (packet.header.markerBit) { + int64_t capture_ms = packet.header.timestamp / 90.0; + int64_t arrival_ms = packet.timestamp / 1000.0; + timestamps.push_back(std::make_pair(capture_ms, arrival_ms)); + } + } + } + return timestamps; +} + void EventLogAnalyzer::CreatePacerDelayGraph(Plot* plot) { - for (const auto& stream : parsed_log_.outgoing_rtp_packets_by_ssrc()) { - const std::vector& packets = - stream.outgoing_packets; + for (const auto& kv : rtp_packets_) { + const std::vector& packets = kv.second; + StreamId stream_id = kv.first; + if (stream_id.GetDirection() == kIncomingPacket) + continue; if (packets.size() < 2) { RTC_LOG(LS_WARNING) @@ -1363,15 +1678,11 @@ void EventLogAnalyzer::CreatePacerDelayGraph(Plot* plot) { "pacer delay with less than 2 packets in the stream"; continue; } - int64_t end_time_us = log_segments_.empty() - ? std::numeric_limits::max() - : log_segments_.front().second; rtc::Optional estimated_frequency = - EstimateRtpClockFrequency(packets, end_time_us); + EstimateRtpClockFrequency(packets); if (!estimated_frequency) continue; - if (IsVideoSsrc(kOutgoingPacket, stream.ssrc) && - *estimated_frequency != 90000) { + if (IsVideoSsrc(stream_id) && *estimated_frequency != 90000) { RTC_LOG(LS_WARNING) << "Video stream should use a 90 kHz clock but appears to use " << *estimated_frequency / 1000 << ". Discarding."; @@ -1379,22 +1690,21 @@ void EventLogAnalyzer::CreatePacerDelayGraph(Plot* plot) { } TimeSeries pacer_delay_series( - GetStreamName(kOutgoingPacket, stream.ssrc) + "(" + + GetStreamName(stream_id) + "(" + std::to_string(*estimated_frequency / 1000) + " kHz)", LineStyle::kLine, PointStyle::kHighlight); SeqNumUnwrapper timestamp_unwrapper; uint64_t first_capture_timestamp = - timestamp_unwrapper.Unwrap(packets.front().rtp.header.timestamp); - uint64_t first_send_timestamp = packets.front().rtp.log_time_us(); - for (const auto& packet : packets) { + timestamp_unwrapper.Unwrap(packets.front().header.timestamp); + uint64_t first_send_timestamp = packets.front().timestamp; + for (LoggedRtpPacket packet : packets) { double capture_time_ms = (static_cast(timestamp_unwrapper.Unwrap( - packet.rtp.header.timestamp)) - + packet.header.timestamp)) - first_capture_timestamp) / *estimated_frequency * 1000; double send_time_ms = - static_cast(packet.rtp.log_time_us() - first_send_timestamp) / - 1000; - float x = ToCallTime(packet.rtp.log_time_us()); + static_cast(packet.timestamp - first_send_timestamp) / 1000; + float x = ToCallTime(packet.timestamp); float y = send_time_ms - capture_time_ms; pacer_delay_series.points.emplace_back(x, y); } @@ -1407,52 +1717,58 @@ void EventLogAnalyzer::CreatePacerDelayGraph(Plot* plot) { "Delay from capture to send time. (First packet normalized to 0.)"); } -void EventLogAnalyzer::CreateTimestampGraph(PacketDirection direction, - Plot* plot) { - for (const auto& stream : parsed_log_.rtp_packets_by_ssrc(direction)) { - TimeSeries rtp_timestamps( - GetStreamName(direction, stream.ssrc) + " capture-time", - LineStyle::kLine, PointStyle::kHighlight); - for (const auto& packet : stream.packet_view) { - float x = ToCallTime(packet.log_time_us()); - float y = packet.header.timestamp; - rtp_timestamps.points.emplace_back(x, y); - } - plot->AppendTimeSeries(std::move(rtp_timestamps)); +void EventLogAnalyzer::CreateTimestampGraph(Plot* plot) { + for (const auto& kv : rtp_packets_) { + const std::vector& rtp_packets = kv.second; + StreamId stream_id = kv.first; - TimeSeries rtcp_timestamps( - GetStreamName(direction, stream.ssrc) + " rtcp capture-time", - LineStyle::kLine, PointStyle::kHighlight); - // TODO(terelius): Why only sender reports? - const auto& sender_reports = parsed_log_.sender_reports(direction); - for (const auto& rtcp : sender_reports) { - if (rtcp.sr.sender_ssrc() != stream.ssrc) - continue; - float x = ToCallTime(rtcp.log_time_us()); - float y = rtcp.sr.rtp_timestamp(); - rtcp_timestamps.points.emplace_back(x, y); + { + TimeSeries timestamp_data(GetStreamName(stream_id) + " capture-time", + LineStyle::kLine, PointStyle::kHighlight); + for (LoggedRtpPacket packet : rtp_packets) { + float x = ToCallTime(packet.timestamp); + float y = packet.header.timestamp; + timestamp_data.points.emplace_back(x, y); + } + plot->AppendTimeSeries(std::move(timestamp_data)); + } + + { + auto kv = rtcp_packets_.find(stream_id); + if (kv != rtcp_packets_.end()) { + const auto& packets = kv->second; + TimeSeries timestamp_data( + GetStreamName(stream_id) + " rtcp capture-time", LineStyle::kLine, + PointStyle::kHighlight); + for (const LoggedRtcpPacket& rtcp : packets) { + if (rtcp.type != kRtcpSr) + continue; + rtcp::SenderReport* sr; + sr = static_cast(rtcp.packet.get()); + float x = ToCallTime(rtcp.timestamp); + float y = sr->rtp_timestamp(); + timestamp_data.points.emplace_back(x, y); + } + plot->AppendTimeSeries(std::move(timestamp_data)); + } } - plot->AppendTimeSeriesIfNotEmpty(std::move(rtcp_timestamps)); } plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); - plot->SetSuggestedYAxis(0, 1, "RTP timestamp", kBottomMargin, kTopMargin); - plot->SetTitle(GetDirectionAsString(direction) + " timestamps"); + plot->SetSuggestedYAxis(0, 1, "Timestamp (90khz)", kBottomMargin, kTopMargin); + plot->SetTitle("Timestamps"); } void EventLogAnalyzer::CreateAudioEncoderTargetBitrateGraph(Plot* plot) { TimeSeries time_series("Audio encoder target bitrate", LineStyle::kLine, PointStyle::kHighlight); - auto GetAnaBitrateBps = [](const LoggedAudioNetworkAdaptationEvent& ana_event) - -> rtc::Optional { - if (ana_event.config.bitrate_bps) - return rtc::Optional( - static_cast(*ana_event.config.bitrate_bps)); - return rtc::nullopt; - }; - ProcessPoints( - GetAnaBitrateBps, parsed_log_.audio_network_adaptation_events(), - begin_time_, &time_series); + ProcessPoints( + [](const AudioNetworkAdaptationEvent& ana_event) -> rtc::Optional { + if (ana_event.config.bitrate_bps) + return static_cast(*ana_event.config.bitrate_bps); + return rtc::nullopt; + }, + audio_network_adaptation_events_, begin_time_, &time_series); plot->AppendTimeSeries(std::move(time_series)); plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); plot->SetSuggestedYAxis(0, 1, "Bitrate (bps)", kBottomMargin, kTopMargin); @@ -1462,16 +1778,14 @@ void EventLogAnalyzer::CreateAudioEncoderTargetBitrateGraph(Plot* plot) { void EventLogAnalyzer::CreateAudioEncoderFrameLengthGraph(Plot* plot) { TimeSeries time_series("Audio encoder frame length", LineStyle::kLine, PointStyle::kHighlight); - auto GetAnaFrameLengthMs = - [](const LoggedAudioNetworkAdaptationEvent& ana_event) { + ProcessPoints( + [](const AudioNetworkAdaptationEvent& ana_event) { if (ana_event.config.frame_length_ms) return rtc::Optional( static_cast(*ana_event.config.frame_length_ms)); return rtc::Optional(); - }; - ProcessPoints( - GetAnaFrameLengthMs, parsed_log_.audio_network_adaptation_events(), - begin_time_, &time_series); + }, + audio_network_adaptation_events_, begin_time_, &time_series); plot->AppendTimeSeries(std::move(time_series)); plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); plot->SetSuggestedYAxis(0, 1, "Frame length (ms)", kBottomMargin, kTopMargin); @@ -1481,16 +1795,14 @@ void EventLogAnalyzer::CreateAudioEncoderFrameLengthGraph(Plot* plot) { void EventLogAnalyzer::CreateAudioEncoderPacketLossGraph(Plot* plot) { TimeSeries time_series("Audio encoder uplink packet loss fraction", LineStyle::kLine, PointStyle::kHighlight); - auto GetAnaPacketLoss = - [](const LoggedAudioNetworkAdaptationEvent& ana_event) { + ProcessPoints( + [](const AudioNetworkAdaptationEvent& ana_event) { if (ana_event.config.uplink_packet_loss_fraction) return rtc::Optional(static_cast( *ana_event.config.uplink_packet_loss_fraction)); return rtc::Optional(); - }; - ProcessPoints( - GetAnaPacketLoss, parsed_log_.audio_network_adaptation_events(), - begin_time_, &time_series); + }, + audio_network_adaptation_events_, begin_time_, &time_series); plot->AppendTimeSeries(std::move(time_series)); plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); plot->SetSuggestedYAxis(0, 10, "Percent lost packets", kBottomMargin, @@ -1501,16 +1813,14 @@ void EventLogAnalyzer::CreateAudioEncoderPacketLossGraph(Plot* plot) { void EventLogAnalyzer::CreateAudioEncoderEnableFecGraph(Plot* plot) { TimeSeries time_series("Audio encoder FEC", LineStyle::kLine, PointStyle::kHighlight); - auto GetAnaFecEnabled = - [](const LoggedAudioNetworkAdaptationEvent& ana_event) { + ProcessPoints( + [](const AudioNetworkAdaptationEvent& ana_event) { if (ana_event.config.enable_fec) return rtc::Optional( static_cast(*ana_event.config.enable_fec)); return rtc::Optional(); - }; - ProcessPoints( - GetAnaFecEnabled, parsed_log_.audio_network_adaptation_events(), - begin_time_, &time_series); + }, + audio_network_adaptation_events_, begin_time_, &time_series); plot->AppendTimeSeries(std::move(time_series)); plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); plot->SetSuggestedYAxis(0, 1, "FEC (false/true)", kBottomMargin, kTopMargin); @@ -1520,16 +1830,14 @@ void EventLogAnalyzer::CreateAudioEncoderEnableFecGraph(Plot* plot) { void EventLogAnalyzer::CreateAudioEncoderEnableDtxGraph(Plot* plot) { TimeSeries time_series("Audio encoder DTX", LineStyle::kLine, PointStyle::kHighlight); - auto GetAnaDtxEnabled = - [](const LoggedAudioNetworkAdaptationEvent& ana_event) { + ProcessPoints( + [](const AudioNetworkAdaptationEvent& ana_event) { if (ana_event.config.enable_dtx) return rtc::Optional( static_cast(*ana_event.config.enable_dtx)); return rtc::Optional(); - }; - ProcessPoints( - GetAnaDtxEnabled, parsed_log_.audio_network_adaptation_events(), - begin_time_, &time_series); + }, + audio_network_adaptation_events_, begin_time_, &time_series); plot->AppendTimeSeries(std::move(time_series)); plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); plot->SetSuggestedYAxis(0, 1, "DTX (false/true)", kBottomMargin, kTopMargin); @@ -1539,16 +1847,14 @@ void EventLogAnalyzer::CreateAudioEncoderEnableDtxGraph(Plot* plot) { void EventLogAnalyzer::CreateAudioEncoderNumChannelsGraph(Plot* plot) { TimeSeries time_series("Audio encoder number of channels", LineStyle::kLine, PointStyle::kHighlight); - auto GetAnaNumChannels = - [](const LoggedAudioNetworkAdaptationEvent& ana_event) { + ProcessPoints( + [](const AudioNetworkAdaptationEvent& ana_event) { if (ana_event.config.num_channels) return rtc::Optional( static_cast(*ana_event.config.num_channels)); return rtc::Optional(); - }; - ProcessPoints( - GetAnaNumChannels, parsed_log_.audio_network_adaptation_events(), - begin_time_, &time_series); + }, + audio_network_adaptation_events_, begin_time_, &time_series); plot->AppendTimeSeries(std::move(time_series)); plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); plot->SetSuggestedYAxis(0, 1, "Number of channels (1 (mono)/2 (stereo))", @@ -1560,9 +1866,9 @@ class NetEqStreamInput : public test::NetEqInput { public: // Does not take any ownership, and all pointers must refer to valid objects // that outlive the one constructed. - NetEqStreamInput(const std::vector* packet_stream, - const std::vector* output_events_us, - rtc::Optional end_time_us) + NetEqStreamInput(const std::vector* packet_stream, + const std::vector* output_events_us, + rtc::Optional end_time_us) : packet_stream_(*packet_stream), packet_stream_it_(packet_stream_.begin()), output_events_us_it_(output_events_us->begin()), @@ -1576,11 +1882,11 @@ class NetEqStreamInput : public test::NetEqInput { if (packet_stream_it_ == packet_stream_.end()) { return rtc::nullopt; } - if (end_time_us_ && packet_stream_it_->rtp.log_time_us() > *end_time_us_) { + if (end_time_us_ && packet_stream_it_->timestamp > *end_time_us_) { return rtc::nullopt; } // Convert from us to ms. - return packet_stream_it_->rtp.log_time_us() / 1000; + return packet_stream_it_->timestamp / 1000; } rtc::Optional NextOutputEventTime() const override { @@ -1599,14 +1905,14 @@ class NetEqStreamInput : public test::NetEqInput { return std::unique_ptr(); } std::unique_ptr packet_data(new PacketData()); - packet_data->header = packet_stream_it_->rtp.header; + packet_data->header = packet_stream_it_->header; // Convert from us to ms. - packet_data->time_ms = packet_stream_it_->rtp.log_time_us() / 1000.0; + packet_data->time_ms = packet_stream_it_->timestamp / 1000.0; // This is a header-only "dummy" packet. Set the payload to all zeros, with // length according to the virtual length. - packet_data->payload.SetSize(packet_stream_it_->rtp.total_length - - packet_stream_it_->rtp.header_length); + packet_data->payload.SetSize(packet_stream_it_->total_length - + packet_stream_it_->header_length); std::fill_n(packet_data->payload.data(), packet_data->payload.size(), 0); ++packet_stream_it_; @@ -1625,15 +1931,15 @@ class NetEqStreamInput : public test::NetEqInput { if (packet_stream_it_ == packet_stream_.end()) { return rtc::nullopt; } - return packet_stream_it_->rtp.header; + return packet_stream_it_->header; } private: - const std::vector& packet_stream_; - std::vector::const_iterator packet_stream_it_; - std::vector::const_iterator output_events_us_it_; - const std::vector::const_iterator output_events_us_end_; - const rtc::Optional end_time_us_; + const std::vector& packet_stream_; + std::vector::const_iterator packet_stream_it_; + std::vector::const_iterator output_events_us_it_; + const std::vector::const_iterator output_events_us_end_; + const rtc::Optional end_time_us_; }; namespace { @@ -1641,9 +1947,9 @@ namespace { // the test and returns the NetEqDelayAnalyzer object that was used to // instrument the test. std::unique_ptr CreateNetEqTestAndRun( - const std::vector* packet_stream, - const std::vector* output_events_us, - rtc::Optional end_time_us, + const std::vector* packet_stream, + const std::vector* output_events_us, + rtc::Optional end_time_us, const std::string& replacement_file_name, int file_sample_rate_hz) { std::unique_ptr input( @@ -1698,35 +2004,34 @@ void EventLogAnalyzer::CreateAudioJitterBufferGraph( const std::string& replacement_file_name, int file_sample_rate_hz, Plot* plot) { - const std::vector* audio_packets = nullptr; - uint32_t ssrc; - for (const auto& stream : parsed_log_.incoming_rtp_packets_by_ssrc()) { - if (IsAudioSsrc(kIncomingPacket, stream.ssrc)) { - audio_packets = &stream.incoming_packets; - ssrc = stream.ssrc; - break; - } - } - if (audio_packets == nullptr) { + const auto& incoming_audio_kv = std::find_if( + rtp_packets_.begin(), rtp_packets_.end(), + [this](std::pair> kv) { + return kv.first.GetDirection() == kIncomingPacket && + this->IsAudioSsrc(kv.first); + }); + if (incoming_audio_kv == rtp_packets_.end()) { // No incoming audio stream found. return; } - std::map>::const_iterator output_events_it = - parsed_log_.audio_playout_events().find(ssrc); - if (output_events_it == parsed_log_.audio_playout_events().end()) { + const uint32_t ssrc = incoming_audio_kv->first.GetSsrc(); + + std::map>::const_iterator output_events_it = + audio_playout_events_.find(ssrc); + if (output_events_it == audio_playout_events_.end()) { // Could not find output events with SSRC matching the input audio stream. // Using the first available stream of output events. - output_events_it = parsed_log_.audio_playout_events().cbegin(); + output_events_it = audio_playout_events_.cbegin(); } - rtc::Optional end_time_us = + rtc::Optional end_time_us = log_segments_.empty() ? rtc::nullopt - : rtc::Optional(log_segments_.front().second); + : rtc::Optional(log_segments_.front().second); auto delay_cb = CreateNetEqTestAndRun( - audio_packets, &output_events_it->second, end_time_us, + &incoming_audio_kv->second, &output_events_it->second, end_time_us, replacement_file_name, file_sample_rate_hz); std::vector send_times_s; @@ -1742,27 +2047,28 @@ void EventLogAnalyzer::CreateAudioJitterBufferGraph( RTC_DCHECK_EQ(send_times_s.size(), playout_delay_ms.size()); RTC_DCHECK_EQ(send_times_s.size(), target_delay_ms.size()); - std::map time_series_packet_arrival; - std::map time_series_relative_packet_arrival; - std::map time_series_play_time; - std::map time_series_target_time; + std::map time_series_packet_arrival; + std::map time_series_relative_packet_arrival; + std::map time_series_play_time; + std::map time_series_target_time; float min_y_axis = 0.f; float max_y_axis = 0.f; + const StreamId stream_id = incoming_audio_kv->first; for (size_t i = 0; i < send_times_s.size(); ++i) { - time_series_packet_arrival[ssrc].points.emplace_back( + time_series_packet_arrival[stream_id].points.emplace_back( TimeSeriesPoint(send_times_s[i], arrival_delay_ms[i])); - time_series_relative_packet_arrival[ssrc].points.emplace_back( + time_series_relative_packet_arrival[stream_id].points.emplace_back( TimeSeriesPoint(send_times_s[i], corrected_arrival_delay_ms[i])); min_y_axis = std::min(min_y_axis, corrected_arrival_delay_ms[i]); max_y_axis = std::max(max_y_axis, corrected_arrival_delay_ms[i]); if (playout_delay_ms[i]) { - time_series_play_time[ssrc].points.emplace_back( + time_series_play_time[stream_id].points.emplace_back( TimeSeriesPoint(send_times_s[i], *playout_delay_ms[i])); min_y_axis = std::min(min_y_axis, *playout_delay_ms[i]); max_y_axis = std::max(max_y_axis, *playout_delay_ms[i]); } if (target_delay_ms[i]) { - time_series_target_time[ssrc].points.emplace_back( + time_series_target_time[stream_id].points.emplace_back( TimeSeriesPoint(send_times_s[i], *target_delay_ms[i])); min_y_axis = std::min(min_y_axis, *target_delay_ms[i]); max_y_axis = std::max(max_y_axis, *target_delay_ms[i]); @@ -1800,7 +2106,7 @@ void EventLogAnalyzer::CreateAudioJitterBufferGraph( void EventLogAnalyzer::CreateIceCandidatePairConfigGraph(Plot* plot) { std::map configs_by_cp_id; - for (const auto& config : parsed_log_.ice_candidate_pair_configs()) { + 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 = @@ -1812,7 +2118,7 @@ void EventLogAnalyzer::CreateIceCandidatePairConfigGraph(Plot* plot) { candidate_pair_desc_by_id_[config.candidate_pair_id] = candidate_pair_desc; } - float x = ToCallTime(config.log_time_us()); + float x = ToCallTime(config.timestamp); float y = static_cast(config.type); configs_by_cp_id[config.candidate_pair_id].points.emplace_back(x, y); } @@ -1836,7 +2142,7 @@ std::string EventLogAnalyzer::GetCandidatePairLogDescriptionFromId( candidate_pair_desc_by_id_.end()) { return candidate_pair_desc_by_id_[candidate_pair_id]; } - for (const auto& config : parsed_log_.ice_candidate_pair_configs()) { + 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) == @@ -1852,7 +2158,7 @@ std::string EventLogAnalyzer::GetCandidatePairLogDescriptionFromId( void EventLogAnalyzer::CreateIceConnectivityCheckGraph(Plot* plot) { std::map checks_by_cp_id; - for (const auto& event : parsed_log_.ice_candidate_pair_events()) { + 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( @@ -1860,7 +2166,7 @@ void EventLogAnalyzer::CreateIceConnectivityCheckGraph(Plot* plot) { GetCandidatePairLogDescriptionFromId(event.candidate_pair_id), LineStyle::kNone, PointStyle::kHighlight); } - float x = ToCallTime(event.log_time_us()); + float x = ToCallTime(event.timestamp); float y = static_cast(event.type); checks_by_cp_id[event.candidate_pair_id].points.emplace_back(x, y); } @@ -1876,176 +2182,163 @@ void EventLogAnalyzer::CreateIceConnectivityCheckGraph(Plot* plot) { plot->SetTitle("[IceEventLog] ICE connectivity checks"); } +void EventLogAnalyzer::Notification( + std::unique_ptr notification) { + notifications_.push_back(std::move(notification)); +} + void EventLogAnalyzer::PrintNotifications(FILE* file) { + if (notifications_.size() == 0) + return; fprintf(file, "========== TRIAGE NOTIFICATIONS ==========\n"); - for (const auto& alert : incoming_rtp_recv_time_gaps_) { - fprintf(file, "%3.3lf s : %s\n", alert.Time(), alert.ToString().c_str()); - } - for (const auto& alert : incoming_rtcp_recv_time_gaps_) { - fprintf(file, "%3.3lf s : %s\n", alert.Time(), alert.ToString().c_str()); - } - for (const auto& alert : outgoing_rtp_send_time_gaps_) { - fprintf(file, "%3.3lf s : %s\n", alert.Time(), alert.ToString().c_str()); - } - for (const auto& alert : outgoing_rtcp_send_time_gaps_) { - fprintf(file, "%3.3lf s : %s\n", alert.Time(), alert.ToString().c_str()); - } - for (const auto& alert : incoming_seq_num_jumps_) { - fprintf(file, "%3.3lf s : %s\n", alert.Time(), alert.ToString().c_str()); - } - for (const auto& alert : incoming_capture_time_jumps_) { - fprintf(file, "%3.3lf s : %s\n", alert.Time(), alert.ToString().c_str()); - } - for (const auto& alert : outgoing_seq_num_jumps_) { - fprintf(file, "%3.3lf s : %s\n", alert.Time(), alert.ToString().c_str()); - } - for (const auto& alert : outgoing_capture_time_jumps_) { - fprintf(file, "%3.3lf s : %s\n", alert.Time(), alert.ToString().c_str()); - } - for (const auto& alert : outgoing_high_loss_alerts_) { - fprintf(file, " : %s\n", alert.ToString().c_str()); + for (const auto& notification : notifications_) { + rtc::Optional call_timestamp = notification->Time(); + if (call_timestamp.has_value()) { + fprintf(file, "%3.3lf s : %s\n", call_timestamp.value(), + notification->ToString().c_str()); + } else { + fprintf(file, " : %s\n", notification->ToString().c_str()); + } } fprintf(file, "========== END TRIAGE NOTIFICATIONS ==========\n"); } -void EventLogAnalyzer::CreateStreamGapAlerts(PacketDirection direction) { - // With 100 packets/s (~800kbps), false positives would require 10 s without - // data. - constexpr int64_t kMaxSeqNumJump = 1000; - // With a 90 kHz clock, false positives would require 10 s without data. - constexpr int64_t kMaxCaptureTimeJump = 900000; - - int64_t end_time_us = log_segments_.empty() - ? std::numeric_limits::max() - : log_segments_.front().second; - - SeqNumUnwrapper seq_num_unwrapper; - rtc::Optional last_seq_num; - SeqNumUnwrapper capture_time_unwrapper; - rtc::Optional last_capture_time; - // Check for gaps in sequence numbers and capture timestamps. - for (const auto& stream : parsed_log_.rtp_packets_by_ssrc(direction)) { - for (const auto& packet : stream.packet_view) { - if (packet.log_time_us() > end_time_us) { - // Only process the first (LOG_START, LOG_END) segment. - break; - } - - int64_t seq_num = seq_num_unwrapper.Unwrap(packet.header.sequenceNumber); - if (last_seq_num.has_value() && - std::abs(seq_num - last_seq_num.value()) > kMaxSeqNumJump) { - Alert_SeqNumJump(direction, ToCallTime(packet.log_time_us()), - packet.header.ssrc); - } - last_seq_num.emplace(seq_num); - - int64_t capture_time = - capture_time_unwrapper.Unwrap(packet.header.timestamp); - if (last_capture_time.has_value() && - std::abs(capture_time - last_capture_time.value()) > - kMaxCaptureTimeJump) { - Alert_CaptureTimeJump(direction, ToCallTime(packet.log_time_us()), - packet.header.ssrc); - } - last_capture_time.emplace(capture_time); - } - } -} - -void EventLogAnalyzer::CreateTransmissionGapAlerts(PacketDirection direction) { - constexpr int64_t kMaxRtpTransmissionGap = 500000; - constexpr int64_t kMaxRtcpTransmissionGap = 2000000; - int64_t end_time_us = log_segments_.empty() - ? std::numeric_limits::max() - : log_segments_.front().second; - - // TODO(terelius): The parser could provide a list of all packets, ordered - // by time, for each direction. - std::multimap rtp_in_direction; - for (const auto& stream : parsed_log_.rtp_packets_by_ssrc(direction)) { - for (const LoggedRtpPacket& rtp_packet : stream.packet_view) - rtp_in_direction.emplace(rtp_packet.log_time_us(), &rtp_packet); - } - rtc::Optional last_rtp_time; - for (const auto& kv : rtp_in_direction) { - int64_t timestamp = kv.first; - if (timestamp > end_time_us) { - // Only process the first (LOG_START, LOG_END) segment. - break; - } - int64_t duration = timestamp - last_rtp_time.value_or(0); - if (last_rtp_time.has_value() && duration > kMaxRtpTransmissionGap) { - // No packet sent/received for more than 500 ms. - Alert_RtpLogTimeGap(direction, ToCallTime(timestamp), duration / 1000); - } - last_rtp_time.emplace(timestamp); - } - - rtc::Optional last_rtcp_time; - if (direction == kIncomingPacket) { - for (const auto& rtcp : parsed_log_.incoming_rtcp_packets()) { - if (rtcp.log_time_us() > end_time_us) { - // Only process the first (LOG_START, LOG_END) segment. - break; - } - int64_t duration = rtcp.log_time_us() - last_rtcp_time.value_or(0); - if (last_rtcp_time.has_value() && duration > kMaxRtcpTransmissionGap) { - // No feedback sent/received for more than 2000 ms. - Alert_RtcpLogTimeGap(direction, ToCallTime(rtcp.log_time_us()), - duration / 1000); - } - last_rtcp_time.emplace(rtcp.log_time_us()); - } - } else { - for (const auto& rtcp : parsed_log_.outgoing_rtcp_packets()) { - if (rtcp.log_time_us() > end_time_us) { - // Only process the first (LOG_START, LOG_END) segment. - break; - } - int64_t duration = rtcp.log_time_us() - last_rtcp_time.value_or(0); - if (last_rtcp_time.has_value() && duration > kMaxRtcpTransmissionGap) { - // No feedback sent/received for more than 2000 ms. - Alert_RtcpLogTimeGap(direction, ToCallTime(rtcp.log_time_us()), - duration / 1000); - } - last_rtcp_time.emplace(rtcp.log_time_us()); - } - } -} - // TODO(terelius): Notifications could possibly be generated by the same code // that produces the graphs. There is some code duplication that could be // avoided, but that might be solved anyway when we move functionality from the // analyzer to the parser. void EventLogAnalyzer::CreateTriageNotifications() { - CreateStreamGapAlerts(kIncomingPacket); - CreateStreamGapAlerts(kOutgoingPacket); - CreateTransmissionGapAlerts(kIncomingPacket); - CreateTransmissionGapAlerts(kOutgoingPacket); + uint64_t end_time_us = log_segments_.empty() + ? std::numeric_limits::max() + : log_segments_.front().second; + // Check for gaps in sequence numbers and capture timestamps. + for (auto& kv : rtp_packets_) { + StreamId stream_id = kv.first; + const std::vector& packet_stream = kv.second; - int64_t end_time_us = log_segments_.empty() - ? std::numeric_limits::max() - : log_segments_.front().second; + SeqNumUnwrapper seq_no_unwrapper; + rtc::Optional last_seq_no; + SeqNumUnwrapper timestamp_unwrapper; + rtc::Optional last_timestamp; + for (const auto& packet : packet_stream) { + if (packet.timestamp > end_time_us) { + // Only process the first (LOG_START, LOG_END) segment. + break; + } + int64_t seq_no = seq_no_unwrapper.Unwrap(packet.header.sequenceNumber); + if (last_seq_no.has_value() && + std::abs(seq_no - last_seq_no.value()) > 1000) { + // With roughly 100 packets per second (~800kbps), this would require 10 + // seconds without data to trigger incorrectly. + if (stream_id.GetDirection() == kIncomingPacket) { + Notification(rtc::MakeUnique( + ToCallTime(packet.timestamp), packet.header.ssrc)); + } else { + Notification(rtc::MakeUnique( + ToCallTime(packet.timestamp), packet.header.ssrc)); + } + } + last_seq_no.emplace(seq_no); + int64_t timestamp = timestamp_unwrapper.Unwrap(packet.header.timestamp); + if (last_timestamp.has_value() && + std::abs(timestamp - last_timestamp.value()) > 900000) { + // With a 90 kHz clock, this would require 10 seconds without data to + // trigger incorrectly. + if (stream_id.GetDirection() == kIncomingPacket) { + Notification(rtc::MakeUnique( + ToCallTime(packet.timestamp), packet.header.ssrc)); + } else { + Notification(rtc::MakeUnique( + ToCallTime(packet.timestamp), packet.header.ssrc)); + } + } + last_timestamp.emplace(timestamp); + } + } + + // Check for gaps in RTP and RTCP streams + for (const auto direction : + {PacketDirection::kIncomingPacket, PacketDirection::kOutgoingPacket}) { + // TODO(terelius): The parser could provide a list of all packets, ordered + // by time, for each direction. + std::multimap rtp_in_direction; + for (const auto& kv : rtp_packets_) { + if (kv.first.GetDirection() == direction) { + for (const LoggedRtpPacket& rtp_packet : kv.second) + rtp_in_direction.emplace(rtp_packet.timestamp, &rtp_packet); + } + } + rtc::Optional last_rtp_packet; + for (const auto& kv : rtp_in_direction) { + uint64_t timestamp = kv.first; + if (timestamp > end_time_us) { + // Only process the first (LOG_START, LOG_END) segment. + break; + } + int64_t duration = timestamp - last_rtp_packet.value_or(0); + if (last_rtp_packet.has_value() && duration > 500000) { + // No incoming packet for more than 500 ms. + if (direction == kIncomingPacket) { + Notification(rtc::MakeUnique( + ToCallTime(timestamp), duration / 1000)); + } else { + Notification(rtc::MakeUnique( + ToCallTime(timestamp), duration / 1000)); + } + } + last_rtp_packet.emplace(timestamp); + } + + // TODO(terelius): The parser could provide a list of all packets, ordered + // by time, for each direction. + std::multimap rtcp_in_direction; + for (const auto& kv : rtcp_packets_) { + if (kv.first.GetDirection() == direction) { + for (const LoggedRtcpPacket& rtcp_packet : kv.second) + rtcp_in_direction.emplace(rtcp_packet.timestamp, &rtcp_packet); + } + } + rtc::Optional last_incoming_rtcp_packet; + for (const auto& kv : rtcp_in_direction) { + uint64_t timestamp = kv.first; + if (timestamp > end_time_us) { + // Only process the first (LOG_START, LOG_END) segment. + break; + } + int64_t duration = timestamp - last_incoming_rtcp_packet.value_or(0); + if (last_incoming_rtcp_packet.has_value() && duration > 2000000) { + // No incoming feedback for more than 2000 ms. + if (direction == kIncomingPacket) { + Notification(rtc::MakeUnique( + ToCallTime(timestamp), duration / 1000)); + } else { + Notification(rtc::MakeUnique( + ToCallTime(timestamp), duration / 1000)); + } + } + last_incoming_rtcp_packet.emplace(timestamp); + } + } - constexpr double kMaxLossFraction = 0.05; // Loss feedback int64_t total_lost_packets = 0; int64_t total_expected_packets = 0; - for (auto& bwe_update : parsed_log_.bwe_loss_updates()) { - if (bwe_update.log_time_us() > end_time_us) { + for (auto& bwe_update : bwe_loss_updates_) { + if (bwe_update.timestamp > end_time_us) { // Only process the first (LOG_START, LOG_END) segment. break; } - int64_t lost_packets = static_cast(bwe_update.fraction_lost) / 255 * + int64_t lost_packets = static_cast(bwe_update.fraction_loss) / 255 * bwe_update.expected_packets; total_lost_packets += lost_packets; total_expected_packets += bwe_update.expected_packets; } double avg_outgoing_loss = static_cast(total_lost_packets) / total_expected_packets; - if (avg_outgoing_loss > kMaxLossFraction) { - Alert_OutgoingHighLoss(avg_outgoing_loss); + if (avg_outgoing_loss > 0.05) { + Notification(rtc::MakeUnique(avg_outgoing_loss)); } } +} // namespace plotting } // namespace webrtc diff --git a/rtc_tools/event_log_visualizer/analyzer.h b/rtc_tools/event_log_visualizer/analyzer.h index b37de21dcf..a8fedb8341 100644 --- a/rtc_tools/event_log_visualizer/analyzer.h +++ b/rtc_tools/event_log_visualizer/analyzer.h @@ -18,12 +18,54 @@ #include #include -#include "logging/rtc_event_log/rtc_event_log_parser2.h" -#include "rtc_base/strings/string_builder.h" +#include "logging/rtc_event_log/rtc_event_log_parser.h" +#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/rtcp_packet.h" +#include "rtc_base/function_view.h" #include "rtc_tools/event_log_visualizer/plot_base.h" #include "rtc_tools/event_log_visualizer/triage_notifications.h" namespace webrtc { +namespace plotting { + +struct LoggedRtpPacket { + LoggedRtpPacket(uint64_t timestamp, + RTPHeader header, + size_t header_length, + size_t total_length) + : timestamp(timestamp), + header(header), + header_length(header_length), + total_length(total_length) {} + uint64_t timestamp; + // TODO(terelius): This allocates space for 15 CSRCs even if none are used. + RTPHeader header; + size_t header_length; + size_t total_length; +}; + +struct LoggedRtcpPacket { + LoggedRtcpPacket(uint64_t timestamp, + RTCPPacketType rtcp_type, + std::unique_ptr rtcp_packet) + : timestamp(timestamp), type(rtcp_type), packet(std::move(rtcp_packet)) {} + uint64_t timestamp; + RTCPPacketType type; + std::unique_ptr packet; +}; + +struct LossBasedBweUpdate { + uint64_t timestamp; + int32_t new_bitrate; + uint8_t fraction_loss; + int32_t expected_packets; +}; + +struct AudioNetworkAdaptationEvent { + uint64_t timestamp; + AudioEncoderRuntimeConfig config; +}; class EventLogAnalyzer { public: @@ -32,13 +74,14 @@ class EventLogAnalyzer { // modified while the EventLogAnalyzer is being used. explicit EventLogAnalyzer(const ParsedRtcEventLog& log); - void CreatePacketGraph(PacketDirection direction, Plot* plot); + void CreatePacketGraph(PacketDirection desired_direction, Plot* plot); - void CreateAccumulatedPacketsGraph(PacketDirection direction, Plot* plot); + void CreateAccumulatedPacketsGraph(PacketDirection desired_direction, + Plot* plot); void CreatePlayoutGraph(Plot* plot); - void CreateAudioLevelGraph(PacketDirection direction, Plot* plot); + void CreateAudioLevelGraph(Plot* plot); void CreateSequenceNumberGraph(Plot* plot); @@ -49,20 +92,19 @@ class EventLogAnalyzer { void CreateFractionLossGraph(Plot* plot); - void CreateTotalIncomingBitrateGraph(Plot* plot); - void CreateTotalOutgoingBitrateGraph(Plot* plot, - bool show_detector_state = false, - bool show_alr_state = false); + void CreateTotalBitrateGraph(PacketDirection desired_direction, + Plot* plot, + bool show_detector_state = false, + bool show_alr_state = false); - void CreateStreamBitrateGraph(PacketDirection direction, Plot* plot); + void CreateStreamBitrateGraph(PacketDirection desired_direction, Plot* plot); void CreateSendSideBweSimulationGraph(Plot* plot); void CreateReceiveSideBweSimulationGraph(Plot* plot); void CreateNetworkDelayFeedbackGraph(Plot* plot); void CreatePacerDelayGraph(Plot* plot); - - void CreateTimestampGraph(PacketDirection direction, Plot* plot); + void CreateTimestampGraph(Plot* plot); void CreateAudioEncoderTargetBitrateGraph(Plot* plot); void CreateAudioEncoderFrameLengthGraph(Plot* plot); @@ -77,114 +119,55 @@ class EventLogAnalyzer { 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; + void CreateTriageNotifications(); void PrintNotifications(FILE* file); private: - bool IsRtxSsrc(PacketDirection direction, uint32_t ssrc) const { - if (direction == kIncomingPacket) { - return parsed_log_.incoming_rtx_ssrcs().find(ssrc) != - parsed_log_.incoming_rtx_ssrcs().end(); - } else { - return parsed_log_.outgoing_rtx_ssrcs().find(ssrc) != - parsed_log_.outgoing_rtx_ssrcs().end(); + class StreamId { + public: + StreamId(uint32_t ssrc, webrtc::PacketDirection direction) + : ssrc_(ssrc), direction_(direction) {} + bool operator<(const StreamId& other) const { + return std::tie(ssrc_, direction_) < + std::tie(other.ssrc_, other.direction_); } - } - - bool IsVideoSsrc(PacketDirection direction, uint32_t ssrc) const { - if (direction == kIncomingPacket) { - return parsed_log_.incoming_video_ssrcs().find(ssrc) != - parsed_log_.incoming_video_ssrcs().end(); - } else { - return parsed_log_.outgoing_video_ssrcs().find(ssrc) != - parsed_log_.outgoing_video_ssrcs().end(); + bool operator==(const StreamId& other) const { + return std::tie(ssrc_, direction_) == + std::tie(other.ssrc_, other.direction_); } - } + uint32_t GetSsrc() const { return ssrc_; } + webrtc::PacketDirection GetDirection() const { return direction_; } - bool IsAudioSsrc(PacketDirection direction, uint32_t ssrc) const { - if (direction == kIncomingPacket) { - return parsed_log_.incoming_audio_ssrcs().find(ssrc) != - parsed_log_.incoming_audio_ssrcs().end(); - } else { - return parsed_log_.outgoing_audio_ssrcs().find(ssrc) != - parsed_log_.outgoing_audio_ssrcs().end(); - } - } + private: + uint32_t ssrc_; + webrtc::PacketDirection direction_; + }; - template - void CreateAccumulatedPacketsTimeSeries(Plot* plot, - const IterableType& packets, - const std::string& label); + template + void CreateAccumulatedPacketsTimeSeries( + PacketDirection desired_direction, + Plot* plot, + const std::map>& packets, + const std::string& label_prefix); - void CreateStreamGapAlerts(PacketDirection direction); - void CreateTransmissionGapAlerts(PacketDirection direction); + bool IsRtxSsrc(StreamId stream_id) const; - std::string GetStreamName(PacketDirection direction, uint32_t ssrc) const { - char buffer[200]; - rtc::SimpleStringBuilder name(buffer); - if (IsAudioSsrc(direction, ssrc)) { - name << "Audio "; - } else if (IsVideoSsrc(direction, ssrc)) { - name << "Video "; - } else { - name << "Unknown "; - } - if (IsRtxSsrc(direction, ssrc)) { - name << "RTX "; - } - if (direction == kIncomingPacket) - name << "(In) "; - else - name << "(Out) "; - name << "SSRC " << ssrc; - return name.str(); - } + bool IsVideoSsrc(StreamId stream_id) const; + + bool IsAudioSsrc(StreamId stream_id) const; + + std::string GetStreamName(StreamId stream_id) const; + + rtc::Optional EstimateRtpClockFrequency( + const std::vector& packets) const; float ToCallTime(int64_t timestamp) const; - void Alert_RtpLogTimeGap(PacketDirection direction, - float time_seconds, - int64_t duration) { - if (direction == kIncomingPacket) { - incoming_rtp_recv_time_gaps_.emplace_back(time_seconds, duration); - } else { - outgoing_rtp_send_time_gaps_.emplace_back(time_seconds, duration); - } - } - - void Alert_RtcpLogTimeGap(PacketDirection direction, - float time_seconds, - int64_t duration) { - if (direction == kIncomingPacket) { - incoming_rtcp_recv_time_gaps_.emplace_back(time_seconds, duration); - } else { - outgoing_rtcp_send_time_gaps_.emplace_back(time_seconds, duration); - } - } - - void Alert_SeqNumJump(PacketDirection direction, - float time_seconds, - uint32_t ssrc) { - if (direction == kIncomingPacket) { - incoming_seq_num_jumps_.emplace_back(time_seconds, ssrc); - } else { - outgoing_seq_num_jumps_.emplace_back(time_seconds, ssrc); - } - } - - void Alert_CaptureTimeJump(PacketDirection direction, - float time_seconds, - uint32_t ssrc) { - if (direction == kIncomingPacket) { - incoming_capture_time_jumps_.emplace_back(time_seconds, ssrc); - } else { - outgoing_capture_time_jumps_.emplace_back(time_seconds, ssrc); - } - } - - void Alert_OutgoingHighLoss(double avg_loss_fraction) { - outgoing_high_loss_alerts_.emplace_back(avg_loss_fraction); - } + void Notification(std::unique_ptr notification); std::string GetCandidatePairLogDescriptionFromId(uint32_t candidate_pair_id); @@ -194,19 +177,50 @@ class EventLogAnalyzer { // If left empty, all SSRCs will be considered relevant. std::vector desired_ssrc_; + // Tracks what each stream is configured for. Note that a single SSRC can be + // in several sets. For example, the SSRC used for sending video over RTX + // will appear in both video_ssrcs_ and rtx_ssrcs_. In the unlikely case that + // an SSRC is reconfigured to a different media type mid-call, it will also + // appear in multiple sets. + std::set rtx_ssrcs_; + std::set video_ssrcs_; + std::set audio_ssrcs_; + + // Maps a stream identifier consisting of ssrc and direction to the parsed + // RTP headers in that stream. Header extensions are parsed if the stream + // has been configured. + std::map> rtp_packets_; + + std::map> rtcp_packets_; + + // Maps an SSRC to the timestamps of parsed audio playout events. + std::map> audio_playout_events_; + // Stores the timestamps for all log segments, in the form of associated start // and end events. - std::vector> log_segments_; + std::vector> log_segments_; - std::vector incoming_rtp_recv_time_gaps_; - std::vector incoming_rtcp_recv_time_gaps_; - std::vector outgoing_rtp_send_time_gaps_; - std::vector outgoing_rtcp_send_time_gaps_; - std::vector incoming_seq_num_jumps_; - std::vector incoming_capture_time_jumps_; - std::vector outgoing_seq_num_jumps_; - std::vector outgoing_capture_time_jumps_; - std::vector outgoing_high_loss_alerts_; + // A list of all updates from the send-side loss-based bandwidth estimator. + std::vector bwe_loss_updates_; + + std::vector audio_network_adaptation_events_; + + std::vector + bwe_probe_cluster_created_events_; + + std::vector bwe_probe_result_events_; + + std::vector bwe_delay_updates_; + + std::vector> notifications_; + + std::vector alr_state_events_; + + std::vector + ice_candidate_pair_configs_; + + std::vector + ice_candidate_pair_events_; std::map candidate_pair_desc_by_id_; @@ -214,17 +228,18 @@ class EventLogAnalyzer { // The generated data points will be |step_| microseconds apart. // Only events occuring at most |window_duration_| microseconds before the // current data point will be part of the average. - int64_t window_duration_; - int64_t step_; + uint64_t window_duration_; + uint64_t step_; // First and last events of the log. - int64_t begin_time_; - int64_t end_time_; + uint64_t begin_time_; + uint64_t end_time_; // Duration (in seconds) of log file. float call_duration_s_; }; +} // namespace plotting } // namespace webrtc #endif // RTC_TOOLS_EVENT_LOG_VISUALIZER_ANALYZER_H_ diff --git a/rtc_tools/event_log_visualizer/main.cc b/rtc_tools/event_log_visualizer/main.cc index 3dce29001a..2e7a79ec3d 100644 --- a/rtc_tools/event_log_visualizer/main.cc +++ b/rtc_tools/event_log_visualizer/main.cc @@ -10,7 +10,7 @@ #include -#include "logging/rtc_event_log/rtc_event_log_parser2.h" +#include "logging/rtc_event_log/rtc_event_log_parser.h" #include "rtc_base/flags.h" #include "rtc_tools/event_log_visualizer/analyzer.h" #include "rtc_tools/event_log_visualizer/plot_base.h" @@ -143,15 +143,10 @@ DEFINE_bool(show_alr_state, false, "Show the state ALR state on the total bitrate graph"); -DEFINE_bool(parse_unconfigured_header_extensions, - true, - "Attempt to parse unconfigured header extensions using the default " - "WebRTC mapping. This can give very misleading results if the " - "application negotiates a different mapping."); - -DEFINE_bool(print_triage_alerts, - false, - "Print triage alerts, i.e. a list of potential problems."); +DEFINE_bool( + print_triage_notifications, + false, + "Print triage notifications, i.e. a list of suspicious looking events."); void SetAllPlotFlags(bool setting); @@ -214,13 +209,7 @@ int main(int argc, char* argv[]) { std::string filename = argv[1]; - webrtc::ParsedRtcEventLog::UnconfiguredHeaderExtensions header_extensions = - webrtc::ParsedRtcEventLog::UnconfiguredHeaderExtensions::kDontParse; - if (FLAG_parse_unconfigured_header_extensions) { - header_extensions = webrtc::ParsedRtcEventLog:: - UnconfiguredHeaderExtensions::kAttemptWebrtcDefaultConfig; - } - webrtc::ParsedRtcEventLog parsed_log(header_extensions); + webrtc::ParsedRtcEventLog parsed_log; if (!parsed_log.ParseFile(filename)) { std::cerr << "Could not parse the entire log file." << std::endl; @@ -229,34 +218,31 @@ int main(int argc, char* argv[]) { << std::endl; } - webrtc::EventLogAnalyzer analyzer(parsed_log); - std::unique_ptr collection( - new webrtc::PythonPlotCollection()); + webrtc::plotting::EventLogAnalyzer analyzer(parsed_log); + std::unique_ptr collection( + new webrtc::plotting::PythonPlotCollection()); if (FLAG_plot_incoming_packet_sizes) { - analyzer.CreatePacketGraph(webrtc::kIncomingPacket, + analyzer.CreatePacketGraph(webrtc::PacketDirection::kIncomingPacket, collection->AppendNewPlot()); } if (FLAG_plot_outgoing_packet_sizes) { - analyzer.CreatePacketGraph(webrtc::kOutgoingPacket, + analyzer.CreatePacketGraph(webrtc::PacketDirection::kOutgoingPacket, collection->AppendNewPlot()); } if (FLAG_plot_incoming_packet_count) { - analyzer.CreateAccumulatedPacketsGraph(webrtc::kIncomingPacket, - collection->AppendNewPlot()); + analyzer.CreateAccumulatedPacketsGraph( + webrtc::PacketDirection::kIncomingPacket, collection->AppendNewPlot()); } if (FLAG_plot_outgoing_packet_count) { - analyzer.CreateAccumulatedPacketsGraph(webrtc::kOutgoingPacket, - collection->AppendNewPlot()); + analyzer.CreateAccumulatedPacketsGraph( + webrtc::PacketDirection::kOutgoingPacket, collection->AppendNewPlot()); } if (FLAG_plot_audio_playout) { analyzer.CreatePlayoutGraph(collection->AppendNewPlot()); } if (FLAG_plot_audio_level) { - analyzer.CreateAudioLevelGraph(webrtc::kIncomingPacket, - collection->AppendNewPlot()); - analyzer.CreateAudioLevelGraph(webrtc::kOutgoingPacket, - collection->AppendNewPlot()); + analyzer.CreateAudioLevelGraph(collection->AppendNewPlot()); } if (FLAG_plot_incoming_sequence_number_delta) { analyzer.CreateSequenceNumberGraph(collection->AppendNewPlot()); @@ -271,19 +257,23 @@ int main(int argc, char* argv[]) { analyzer.CreateIncomingPacketLossGraph(collection->AppendNewPlot()); } if (FLAG_plot_incoming_bitrate) { - analyzer.CreateTotalIncomingBitrateGraph(collection->AppendNewPlot()); + analyzer.CreateTotalBitrateGraph(webrtc::PacketDirection::kIncomingPacket, + collection->AppendNewPlot(), + FLAG_show_detector_state, + FLAG_show_alr_state); } if (FLAG_plot_outgoing_bitrate) { - analyzer.CreateTotalOutgoingBitrateGraph(collection->AppendNewPlot(), - FLAG_show_detector_state, - FLAG_show_alr_state); + analyzer.CreateTotalBitrateGraph(webrtc::PacketDirection::kOutgoingPacket, + collection->AppendNewPlot(), + FLAG_show_detector_state, + FLAG_show_alr_state); } if (FLAG_plot_incoming_stream_bitrate) { - analyzer.CreateStreamBitrateGraph(webrtc::kIncomingPacket, + analyzer.CreateStreamBitrateGraph(webrtc::PacketDirection::kIncomingPacket, collection->AppendNewPlot()); } if (FLAG_plot_outgoing_stream_bitrate) { - analyzer.CreateStreamBitrateGraph(webrtc::kOutgoingPacket, + analyzer.CreateStreamBitrateGraph(webrtc::PacketDirection::kOutgoingPacket, collection->AppendNewPlot()); } if (FLAG_plot_simulated_receiveside_bwe) { @@ -299,10 +289,7 @@ int main(int argc, char* argv[]) { analyzer.CreateFractionLossGraph(collection->AppendNewPlot()); } if (FLAG_plot_timestamps) { - analyzer.CreateTimestampGraph(webrtc::kIncomingPacket, - collection->AppendNewPlot()); - analyzer.CreateTimestampGraph(webrtc::kOutgoingPacket, - collection->AppendNewPlot()); + analyzer.CreateTimestampGraph(collection->AppendNewPlot()); } if (FLAG_plot_pacer_delay) { analyzer.CreatePacerDelayGraph(collection->AppendNewPlot()); @@ -346,7 +333,7 @@ int main(int argc, char* argv[]) { collection->Draw(); - if (FLAG_print_triage_alerts) { + if (FLAG_print_triage_notifications) { analyzer.CreateTriageNotifications(); analyzer.PrintNotifications(stderr); } diff --git a/rtc_tools/event_log_visualizer/plot_base.cc b/rtc_tools/event_log_visualizer/plot_base.cc index 9a21393792..7ff4ef9c2c 100644 --- a/rtc_tools/event_log_visualizer/plot_base.cc +++ b/rtc_tools/event_log_visualizer/plot_base.cc @@ -15,6 +15,7 @@ #include "rtc_base/checks.h" namespace webrtc { +namespace plotting { void Plot::SetXAxis(float min_value, float max_value, @@ -84,4 +85,5 @@ void Plot::AppendTimeSeriesIfNotEmpty(TimeSeries&& time_series) { } } +} // namespace plotting } // namespace webrtc diff --git a/rtc_tools/event_log_visualizer/plot_base.h b/rtc_tools/event_log_visualizer/plot_base.h index e73f004937..700ffbf02d 100644 --- a/rtc_tools/event_log_visualizer/plot_base.h +++ b/rtc_tools/event_log_visualizer/plot_base.h @@ -16,6 +16,7 @@ #include namespace webrtc { +namespace plotting { enum class LineStyle { kNone, // No line connecting the points. Used to create scatter plots. @@ -172,6 +173,7 @@ class PlotCollection { std::vector > plots_; }; +} // namespace plotting } // namespace webrtc #endif // RTC_TOOLS_EVENT_LOG_VISUALIZER_PLOT_BASE_H_ diff --git a/rtc_tools/event_log_visualizer/plot_protobuf.cc b/rtc_tools/event_log_visualizer/plot_protobuf.cc index e986a74fdc..e5e0a8b094 100644 --- a/rtc_tools/event_log_visualizer/plot_protobuf.cc +++ b/rtc_tools/event_log_visualizer/plot_protobuf.cc @@ -13,6 +13,7 @@ #include namespace webrtc { +namespace plotting { ProtobufPlot::ProtobufPlot() {} @@ -82,4 +83,5 @@ Plot* ProtobufPlotCollection::AppendNewPlot() { return plot; } +} // namespace plotting } // namespace webrtc diff --git a/rtc_tools/event_log_visualizer/plot_protobuf.h b/rtc_tools/event_log_visualizer/plot_protobuf.h index f59d303f1e..5c5cce1242 100644 --- a/rtc_tools/event_log_visualizer/plot_protobuf.h +++ b/rtc_tools/event_log_visualizer/plot_protobuf.h @@ -17,6 +17,7 @@ RTC_POP_IGNORING_WUNDEF() #include "rtc_tools/event_log_visualizer/plot_base.h" namespace webrtc { +namespace plotting { class ProtobufPlot final : public Plot { public: @@ -35,6 +36,7 @@ class ProtobufPlotCollection final : public PlotCollection { void ExportProtobuf(webrtc::analytics::ChartCollection* collection); }; +} // namespace plotting } // namespace webrtc #endif // RTC_TOOLS_EVENT_LOG_VISUALIZER_PLOT_PROTOBUF_H_ diff --git a/rtc_tools/event_log_visualizer/plot_python.cc b/rtc_tools/event_log_visualizer/plot_python.cc index 37c4d84b0a..8f406e2898 100644 --- a/rtc_tools/event_log_visualizer/plot_python.cc +++ b/rtc_tools/event_log_visualizer/plot_python.cc @@ -17,6 +17,7 @@ #include "rtc_base/checks.h" namespace webrtc { +namespace plotting { PythonPlot::PythonPlot() {} @@ -179,4 +180,5 @@ Plot* PythonPlotCollection::AppendNewPlot() { return plot; } +} // namespace plotting } // namespace webrtc diff --git a/rtc_tools/event_log_visualizer/plot_python.h b/rtc_tools/event_log_visualizer/plot_python.h index 61d17a0de3..2a5a66c31c 100644 --- a/rtc_tools/event_log_visualizer/plot_python.h +++ b/rtc_tools/event_log_visualizer/plot_python.h @@ -13,6 +13,7 @@ #include "rtc_tools/event_log_visualizer/plot_base.h" namespace webrtc { +namespace plotting { class PythonPlot final : public Plot { public: @@ -29,6 +30,7 @@ class PythonPlotCollection final : public PlotCollection { Plot* AppendNewPlot() override; }; +} // namespace plotting } // namespace webrtc #endif // RTC_TOOLS_EVENT_LOG_VISUALIZER_PLOT_PYTHON_H_ diff --git a/rtc_tools/event_log_visualizer/triage_notifications.h b/rtc_tools/event_log_visualizer/triage_notifications.h index 49e0620934..641e2ae6b0 100644 --- a/rtc_tools/event_log_visualizer/triage_notifications.h +++ b/rtc_tools/event_log_visualizer/triage_notifications.h @@ -14,136 +14,130 @@ #include namespace webrtc { +namespace plotting { -class IncomingRtpReceiveTimeGap { +class TriageNotification { + public: + TriageNotification() : time_seconds_() {} + explicit TriageNotification(float time_seconds) + : time_seconds_(time_seconds) {} + virtual ~TriageNotification() = default; + virtual std::string ToString() = 0; + rtc::Optional Time() { return time_seconds_; } + + private: + rtc::Optional time_seconds_; +}; + +class IncomingRtpReceiveTimeGap : public TriageNotification { public: IncomingRtpReceiveTimeGap(float time_seconds, int64_t duration) - : time_seconds_(time_seconds), duration_(duration) {} - float Time() const { return time_seconds_; } - std::string ToString() const { + : TriageNotification(time_seconds), duration_(duration) {} + std::string ToString() { return std::string("No RTP packets received for ") + std::to_string(duration_) + std::string(" ms"); } private: - float time_seconds_; int64_t duration_; }; -class IncomingRtcpReceiveTimeGap { +class IncomingRtcpReceiveTimeGap : public TriageNotification { public: IncomingRtcpReceiveTimeGap(float time_seconds, int64_t duration) - : time_seconds_(time_seconds), duration_(duration) {} - float Time() const { return time_seconds_; } - std::string ToString() const { + : TriageNotification(time_seconds), duration_(duration) {} + std::string ToString() { return std::string("No RTCP packets received for ") + std::to_string(duration_) + std::string(" ms"); } private: - float time_seconds_; int64_t duration_; }; -class OutgoingRtpSendTimeGap { +class OutgoingRtpSendTimeGap : public TriageNotification { public: OutgoingRtpSendTimeGap(float time_seconds, int64_t duration) - : time_seconds_(time_seconds), duration_(duration) {} - float Time() const { return time_seconds_; } - std::string ToString() const { + : TriageNotification(time_seconds), duration_(duration) {} + std::string ToString() { return std::string("No RTP packets sent for ") + std::to_string(duration_) + std::string(" ms"); } private: - float time_seconds_; int64_t duration_; }; -class OutgoingRtcpSendTimeGap { +class OutgoingRtcpSendTimeGap : public TriageNotification { public: OutgoingRtcpSendTimeGap(float time_seconds, int64_t duration) - : time_seconds_(time_seconds), duration_(duration) {} - float Time() const { return time_seconds_; } - std::string ToString() const { + : TriageNotification(time_seconds), duration_(duration) {} + std::string ToString() { return std::string("No RTCP packets sent for ") + std::to_string(duration_) + std::string(" ms"); } private: - float time_seconds_; int64_t duration_; }; -class IncomingSeqNumJump { +class IncomingSeqNoJump : public TriageNotification { public: - IncomingSeqNumJump(float time_seconds, uint32_t ssrc) - : time_seconds_(time_seconds), ssrc_(ssrc) {} - float Time() const { return time_seconds_; } - std::string ToString() const { + IncomingSeqNoJump(float time_seconds, uint32_t ssrc) + : TriageNotification(time_seconds), ssrc_(ssrc) {} + std::string ToString() { return std::string("Sequence number jumps on incoming SSRC ") + std::to_string(ssrc_); } private: - float time_seconds_; - uint32_t ssrc_; }; -class IncomingCaptureTimeJump { +class IncomingCaptureTimeJump : public TriageNotification { public: IncomingCaptureTimeJump(float time_seconds, uint32_t ssrc) - : time_seconds_(time_seconds), ssrc_(ssrc) {} - float Time() const { return time_seconds_; } - std::string ToString() const { + : TriageNotification(time_seconds), ssrc_(ssrc) {} + std::string ToString() { return std::string("Capture timestamp jumps on incoming SSRC ") + std::to_string(ssrc_); } private: - float time_seconds_; - uint32_t ssrc_; }; -class OutgoingSeqNoJump { +class OutgoingSeqNoJump : public TriageNotification { public: OutgoingSeqNoJump(float time_seconds, uint32_t ssrc) - : time_seconds_(time_seconds), ssrc_(ssrc) {} - float Time() const { return time_seconds_; } - std::string ToString() const { + : TriageNotification(time_seconds), ssrc_(ssrc) {} + std::string ToString() { return std::string("Sequence number jumps on outgoing SSRC ") + std::to_string(ssrc_); } private: - float time_seconds_; - uint32_t ssrc_; }; -class OutgoingCaptureTimeJump { +class OutgoingCaptureTimeJump : public TriageNotification { public: OutgoingCaptureTimeJump(float time_seconds, uint32_t ssrc) - : time_seconds_(time_seconds), ssrc_(ssrc) {} - float Time() const { return time_seconds_; } - std::string ToString() const { + : TriageNotification(time_seconds), ssrc_(ssrc) {} + std::string ToString() { return std::string("Capture timestamp jumps on outgoing SSRC ") + std::to_string(ssrc_); } private: - float time_seconds_; - uint32_t ssrc_; }; -class OutgoingHighLoss { +class OutgoingHighLoss : public TriageNotification { public: explicit OutgoingHighLoss(double avg_loss_fraction) : avg_loss_fraction_(avg_loss_fraction) {} - std::string ToString() const { + std::string ToString() { return std::string("High average loss (") + std::to_string(avg_loss_fraction_ * 100) + std::string("%) across the call."); @@ -153,6 +147,7 @@ class OutgoingHighLoss { double avg_loss_fraction_; }; +} // namespace plotting } // namespace webrtc #endif // RTC_TOOLS_EVENT_LOG_VISUALIZER_TRIAGE_NOTIFICATIONS_H_