diff --git a/rtc_tools/rtc_event_log_visualizer/analyzer.cc b/rtc_tools/rtc_event_log_visualizer/analyzer.cc index 7b8586a8d1..899cc5b7ac 100644 --- a/rtc_tools/rtc_event_log_visualizer/analyzer.cc +++ b/rtc_tools/rtc_event_log_visualizer/analyzer.cc @@ -66,6 +66,7 @@ #include "rtc_base/numerics/sequence_number_unwrapper.h" #include "rtc_base/rate_statistics.h" #include "rtc_base/strings/string_builder.h" +#include "rtc_tools/rtc_event_log_visualizer/analyze_audio.h" #include "rtc_tools/rtc_event_log_visualizer/analyzer_common.h" #include "rtc_tools/rtc_event_log_visualizer/log_simulation.h" #include "rtc_tools/rtc_event_log_visualizer/plot_base.h" @@ -428,6 +429,22 @@ struct PacketLossSummary { Timestamp base_time = Timestamp::MinusInfinity(); }; +float GetHighestSeqNumber(const webrtc::rtcp::ReportBlock& block) { + return block.extended_high_seq_num(); +} + +float GetFractionLost(const webrtc::rtcp::ReportBlock& block) { + return static_cast(block.fraction_lost()) / 256 * 100; +} + +float GetCumulativeLost(const webrtc::rtcp::ReportBlock& block) { + return block.cumulative_lost(); +} + +float DelaySinceLastSr(const webrtc::rtcp::ReportBlock& block) { + return static_cast(block.delay_since_last_sr()) / 65536; +} + } // namespace EventLogAnalyzer::EventLogAnalyzer(const ParsedRtcEventLog& log, @@ -490,6 +507,201 @@ class BitrateObserver : public RemoteBitrateObserver { bool bitrate_updated_; }; +void EventLogAnalyzer::InitializeMapOfNamedGraphs(bool show_detector_state, + bool show_alr_state, + bool show_link_capacity) { + plots_.RegisterPlot("incoming_packet_sizes", [this](Plot* plot) { + this->CreatePacketGraph(webrtc::kIncomingPacket, plot); + }); + + plots_.RegisterPlot("outgoing_packet_sizes", [this](Plot* plot) { + this->CreatePacketGraph(webrtc::kOutgoingPacket, plot); + }); + plots_.RegisterPlot("incoming_rtcp_types", [this](Plot* plot) { + this->CreateRtcpTypeGraph(webrtc::kIncomingPacket, plot); + }); + plots_.RegisterPlot("outgoing_rtcp_types", [this](Plot* plot) { + this->CreateRtcpTypeGraph(webrtc::kOutgoingPacket, plot); + }); + plots_.RegisterPlot("incoming_packet_count", [this](Plot* plot) { + this->CreateAccumulatedPacketsGraph(webrtc::kIncomingPacket, plot); + }); + plots_.RegisterPlot("outgoing_packet_count", [this](Plot* plot) { + this->CreateAccumulatedPacketsGraph(webrtc::kOutgoingPacket, plot); + }); + plots_.RegisterPlot("incoming_packet_rate", [this](Plot* plot) { + this->CreatePacketRateGraph(webrtc::kIncomingPacket, plot); + }); + plots_.RegisterPlot("outgoing_packet_rate", [this](Plot* plot) { + this->CreatePacketRateGraph(webrtc::kOutgoingPacket, plot); + }); + plots_.RegisterPlot("total_incoming_packet_rate", [this](Plot* plot) { + this->CreateTotalPacketRateGraph(webrtc::kIncomingPacket, plot); + }); + plots_.RegisterPlot("total_outgoing_packet_rate", [this](Plot* plot) { + this->CreateTotalPacketRateGraph(webrtc::kOutgoingPacket, plot); + }); + plots_.RegisterPlot("audio_playout", + [this](Plot* plot) { this->CreatePlayoutGraph(plot); }); + + plots_.RegisterPlot("neteq_set_minimum_delay", [this](Plot* plot) { + this->CreateNetEqSetMinimumDelay(plot); + }); + + plots_.RegisterPlot("incoming_audio_level", [this](Plot* plot) { + this->CreateAudioLevelGraph(webrtc::kIncomingPacket, plot); + }); + plots_.RegisterPlot("outgoing_audio_level", [this](Plot* plot) { + this->CreateAudioLevelGraph(webrtc::kOutgoingPacket, plot); + }); + plots_.RegisterPlot("incoming_sequence_number_delta", [this](Plot* plot) { + this->CreateSequenceNumberGraph(plot); + }); + plots_.RegisterPlot("incoming_delay", [this](Plot* plot) { + this->CreateIncomingDelayGraph(plot); + }); + plots_.RegisterPlot("incoming_loss_rate", [this](Plot* plot) { + this->CreateIncomingPacketLossGraph(plot); + }); + plots_.RegisterPlot("incoming_bitrate", [this](Plot* plot) { + this->CreateTotalIncomingBitrateGraph(plot); + }); + plots_.RegisterPlot( + "outgoing_bitrate", [this, show_detector_state, show_alr_state, + show_link_capacity](Plot* plot) { + this->CreateTotalOutgoingBitrateGraph( + plot, show_detector_state, show_alr_state, show_link_capacity); + }); + plots_.RegisterPlot("incoming_stream_bitrate", [this](Plot* plot) { + this->CreateStreamBitrateGraph(webrtc::kIncomingPacket, plot); + }); + plots_.RegisterPlot("outgoing_stream_bitrate", [this](Plot* plot) { + this->CreateStreamBitrateGraph(webrtc::kOutgoingPacket, plot); + }); + plots_.RegisterPlot("incoming_layer_bitrate_allocation", [this](Plot* plot) { + this->CreateBitrateAllocationGraph(webrtc::kIncomingPacket, plot); + }); + plots_.RegisterPlot("outgoing_layer_bitrate_allocation", [this](Plot* plot) { + this->CreateBitrateAllocationGraph(webrtc::kOutgoingPacket, plot); + }); + plots_.RegisterPlot("simulated_receiveside_bwe", [this](Plot* plot) { + this->CreateReceiveSideBweSimulationGraph(plot); + }); + plots_.RegisterPlot("simulated_sendside_bwe", [this](Plot* plot) { + this->CreateSendSideBweSimulationGraph(plot); + }); + plots_.RegisterPlot("simulated_goog_cc", [this](Plot* plot) { + this->CreateGoogCcSimulationGraph(plot); + }); + plots_.RegisterPlot("outgoing_twcc_loss", [this](Plot* plot) { + this->CreateOutgoingTWCCLossRateGraph(plot); + }); + plots_.RegisterPlot("network_delay_feedback", [this](Plot* plot) { + this->CreateNetworkDelayFeedbackGraph(plot); + }); + plots_.RegisterPlot("fraction_loss_feedback", [this](Plot* plot) { + this->CreateFractionLossGraph(plot); + }); + plots_.RegisterPlot("incoming_timestamps", [this](Plot* plot) { + this->CreateTimestampGraph(webrtc::kIncomingPacket, plot); + }); + plots_.RegisterPlot("outgoing_timestamps", [this](Plot* plot) { + this->CreateTimestampGraph(webrtc::kOutgoingPacket, plot); + }); + + plots_.RegisterPlot("incoming_rtcp_fraction_lost", [this](Plot* plot) { + this->CreateSenderAndReceiverReportPlot( + webrtc::kIncomingPacket, GetFractionLost, + "Fraction lost (incoming RTCP)", "Loss rate (percent)", plot); + }); + plots_.RegisterPlot("outgoing_rtcp_fraction_lost", [this](Plot* plot) { + this->CreateSenderAndReceiverReportPlot( + webrtc::kOutgoingPacket, GetFractionLost, + "Fraction lost (outgoing RTCP)", "Loss rate (percent)", plot); + }); + + plots_.RegisterPlot("incoming_rtcp_cumulative_lost", [this](Plot* plot) { + this->CreateSenderAndReceiverReportPlot( + webrtc::kIncomingPacket, GetCumulativeLost, + "Cumulative lost packets (incoming RTCP)", "Packets", plot); + }); + plots_.RegisterPlot("outgoing_rtcp_cumulative_lost", [this](Plot* plot) { + this->CreateSenderAndReceiverReportPlot( + webrtc::kOutgoingPacket, GetCumulativeLost, + "Cumulative lost packets (outgoing RTCP)", "Packets", plot); + }); + + plots_.RegisterPlot("incoming_rtcp_highest_seq_number", [this](Plot* plot) { + this->CreateSenderAndReceiverReportPlot( + webrtc::kIncomingPacket, GetHighestSeqNumber, + "Highest sequence number (incoming RTCP)", "Sequence number", plot); + }); + plots_.RegisterPlot("outgoing_rtcp_highest_seq_number", [this](Plot* plot) { + this->CreateSenderAndReceiverReportPlot( + webrtc::kOutgoingPacket, GetHighestSeqNumber, + "Highest sequence number (outgoing RTCP)", "Sequence number", plot); + }); + + plots_.RegisterPlot("incoming_rtcp_delay_since_last_sr", [this](Plot* plot) { + this->CreateSenderAndReceiverReportPlot( + webrtc::kIncomingPacket, DelaySinceLastSr, + "Delay since last received sender report (incoming RTCP)", "Time (s)", + plot); + }); + plots_.RegisterPlot("outgoing_rtcp_delay_since_last_sr", [this](Plot* plot) { + this->CreateSenderAndReceiverReportPlot( + webrtc::kOutgoingPacket, DelaySinceLastSr, + "Delay since last received sender report (outgoing RTCP)", "Time (s)", + plot); + }); + + plots_.RegisterPlot( + "pacer_delay", [this](Plot* plot) { this->CreatePacerDelayGraph(plot); }); + + plots_.RegisterPlot("audio_encoder_bitrate", [this](Plot* plot) { + CreateAudioEncoderTargetBitrateGraph(this->parsed_log_, this->config_, + plot); + }); + plots_.RegisterPlot("audio_encoder_frame_length", [this](Plot* plot) { + CreateAudioEncoderFrameLengthGraph(this->parsed_log_, this->config_, plot); + }); + plots_.RegisterPlot("audio_encoder_packet_loss", [this](Plot* plot) { + CreateAudioEncoderPacketLossGraph(this->parsed_log_, this->config_, plot); + }); + plots_.RegisterPlot("audio_encoder_fec", [this](Plot* plot) { + CreateAudioEncoderEnableFecGraph(this->parsed_log_, this->config_, plot); + }); + plots_.RegisterPlot("audio_encoder_dtx", [this](Plot* plot) { + CreateAudioEncoderEnableDtxGraph(this->parsed_log_, this->config_, plot); + }); + plots_.RegisterPlot("audio_encoder_num_channels", [this](Plot* plot) { + CreateAudioEncoderNumChannelsGraph(this->parsed_log_, this->config_, plot); + }); + + plots_.RegisterPlot("ice_candidate_pair_config", [this](Plot* plot) { + this->CreateIceCandidatePairConfigGraph(plot); + }); + plots_.RegisterPlot("ice_connectivity_check", [this](Plot* plot) { + this->CreateIceConnectivityCheckGraph(plot); + }); + plots_.RegisterPlot("dtls_transport_state", [this](Plot* plot) { + this->CreateDtlsTransportStateGraph(plot); + }); + plots_.RegisterPlot("dtls_writable_state", [this](Plot* plot) { + this->CreateDtlsWritableStateGraph(plot); + }); +} + +void EventLogAnalyzer::CreateGraphsByName(const std::vector& names, + PlotCollection* collection) { + for (const auto& plot : plots_) { + if (absl::c_find(names, plot.label) != names.end()) { + Plot* output = collection->AppendNewPlot(plot.label); + plot.plot_func(output); + } + } +} + void EventLogAnalyzer::CreatePacketGraph(PacketDirection direction, Plot* plot) { for (const auto& stream : parsed_log_.rtp_packets_by_ssrc(direction)) { diff --git a/rtc_tools/rtc_event_log_visualizer/analyzer.h b/rtc_tools/rtc_event_log_visualizer/analyzer.h index 3dfd5de616..a29454e5b7 100644 --- a/rtc_tools/rtc_event_log_visualizer/analyzer.h +++ b/rtc_tools/rtc_event_log_visualizer/analyzer.h @@ -26,6 +26,31 @@ namespace webrtc { class EventLogAnalyzer { + struct PlotDeclaration { + PlotDeclaration(const std::string& label, std::function f) + : label(label), plot_func(f) {} + const std::string label; + // TODO(terelius): Add a help text/explanation. + const std::function plot_func; + }; + + class PlotMap { + public: + void RegisterPlot(const std::string& label, std::function f) { + for (const auto& plot : plots_) { + RTC_DCHECK(plot.label != label) + << "Can't use the same label for multiple plots"; + } + plots_.push_back({label, f}); + } + + std::vector::iterator begin() { return plots_.begin(); } + std::vector::iterator end() { return plots_.end(); } + + private: + std::vector plots_; + }; + public: // The EventLogAnalyzer keeps a reference to the ParsedRtcEventLogNew for the // duration of its lifetime. The ParsedRtcEventLogNew must not be destroyed or @@ -33,6 +58,21 @@ class EventLogAnalyzer { EventLogAnalyzer(const ParsedRtcEventLog& log, bool normalize_time); EventLogAnalyzer(const ParsedRtcEventLog& log, const AnalyzerConfig& config); + void CreateGraphsByName(const std::vector& names, + PlotCollection* collection); + + void InitializeMapOfNamedGraphs(bool show_detector_state, + bool show_alr_state, + bool show_link_capacity); + + std::vector GetGraphNames() { + std::vector plot_names; + for (const auto& plot : plots_) { + plot_names.push_back(plot.label); + } + return plot_names; + } + void CreatePacketGraph(PacketDirection direction, Plot* plot); void CreateRtcpTypeGraph(PacketDirection direction, Plot* plot); @@ -108,6 +148,8 @@ class EventLogAnalyzer { std::map candidate_pair_desc_by_id_; AnalyzerConfig config_; + + PlotMap plots_; }; } // namespace webrtc diff --git a/rtc_tools/rtc_event_log_visualizer/main.cc b/rtc_tools/rtc_event_log_visualizer/main.cc index e9a747ceb7..8cc449651b 100644 --- a/rtc_tools/rtc_event_log_visualizer/main.cc +++ b/rtc_tools/rtc_event_log_visualizer/main.cc @@ -129,71 +129,10 @@ std::vector StrSplit(const std::string& s, return v; } -struct PlotDeclaration { - PlotDeclaration(const std::string& label, std::function f) - : label(label), enabled(false), plot_func(f) {} - const std::string label; - bool enabled; - // TODO(terelius): Add a help text/explanation. - const std::function plot_func; -}; - -class PlotMap { - public: - void RegisterPlot(const std::string& label, std::function f) { - for (const auto& plot : plots_) { - RTC_DCHECK(plot.label != label) - << "Can't use the same label for multiple plots"; - } - plots_.push_back({label, f}); - } - - bool EnablePlotsByFlags( - const std::vector& flags, - const std::map>& flag_aliases) { - bool status = true; - for (const std::string& flag : flags) { - auto alias_it = flag_aliases.find(flag); - if (alias_it != flag_aliases.end()) { - const auto& replacements = alias_it->second; - for (const auto& replacement : replacements) { - status &= EnablePlotByFlag(replacement); - } - } else { - status &= EnablePlotByFlag(flag); - } - } - return status; - } - - void EnableAllPlots() { - for (auto& plot : plots_) { - plot.enabled = true; - } - } - - std::vector::iterator begin() { return plots_.begin(); } - std::vector::iterator end() { return plots_.end(); } - - private: - bool EnablePlotByFlag(const std::string& flag) { - for (auto& plot : plots_) { - if (plot.label == flag) { - plot.enabled = true; - return true; - } - } - if (flag == "simulated_neteq_jitter_buffer_delay") { - // This flag is handled separately. - return true; - } - std::cerr << "Unrecognized plot name \'" << flag << "\'. Aborting." - << std::endl; - return false; - } - - std::vector plots_; -}; +bool KnownPlotName(absl::string_view name, + const std::vector& known_plots) { + return absl::c_find(known_plots, name) != known_plots.end(); +} bool ContainsHelppackageFlags(absl::string_view filename) { return absl::EndsWith(filename, "main.cc"); @@ -217,37 +156,6 @@ int main(int argc, char* argv[]) { } rtc::LogMessage::SetLogToStderr(true); - // Flag replacements - std::map> flag_aliases = { - {"default", - {"incoming_delay", "incoming_loss_rate", "incoming_bitrate", - "outgoing_bitrate", "incoming_stream_bitrate", - "outgoing_stream_bitrate", "network_delay_feedback", - "fraction_loss_feedback"}}, - {"sendside_bwe", - {"outgoing_packet_sizes", "outgoing_bitrate", "outgoing_stream_bitrate", - "simulated_sendside_bwe", "network_delay_feedback", - "fraction_loss_feedback", "outgoing_twcc_loss"}}, - {"receiveside_bwe", - {"incoming_packet_sizes", "incoming_delay", "incoming_loss_rate", - "incoming_bitrate", "incoming_stream_bitrate", - "simulated_receiveside_bwe"}}, - {"rtcp_details", - {"incoming_rtcp_fraction_lost", "outgoing_rtcp_fraction_lost", - "incoming_rtcp_cumulative_lost", "outgoing_rtcp_cumulative_lost", - "incoming_rtcp_highest_seq_number", "outgoing_rtcp_highest_seq_number", - "incoming_rtcp_delay_since_last_sr", - "outgoing_rtcp_delay_since_last_sr"}}, - {"simulated_neteq_stats", - {"simulated_neteq_jitter_buffer_delay", - "simulated_neteq_preferred_buffer_size", - "simulated_neteq_concealment_events", "simulated_neteq_preemptive_rate", - "simulated_neteq_accelerate_rate", "simulated_neteq_speech_expand_rate", - "simulated_neteq_expand_rate"}}}; - - std::vector plot_flags = - StrSplit(absl::GetFlag(FLAGS_plot), ","); - // InitFieldTrialsFromString stores the char*, so the char array must outlive // the application. const std::string field_trials = absl::GetFlag(FLAGS_force_fieldtrials); @@ -289,202 +197,6 @@ int main(int argc, char* argv[]) { return -1; } - webrtc::EventLogAnalyzer analyzer(parsed_log, config); - webrtc::PlotCollection collection; - collection.SetCallTimeToUtcOffsetMs(config.CallTimeToUtcOffsetMs()); - - PlotMap plots; - plots.RegisterPlot("incoming_packet_sizes", [&](Plot* plot) { - analyzer.CreatePacketGraph(webrtc::kIncomingPacket, plot); - }); - - plots.RegisterPlot("outgoing_packet_sizes", [&](Plot* plot) { - analyzer.CreatePacketGraph(webrtc::kOutgoingPacket, plot); - }); - plots.RegisterPlot("incoming_rtcp_types", [&](Plot* plot) { - analyzer.CreateRtcpTypeGraph(webrtc::kIncomingPacket, plot); - }); - plots.RegisterPlot("outgoing_rtcp_types", [&](Plot* plot) { - analyzer.CreateRtcpTypeGraph(webrtc::kOutgoingPacket, plot); - }); - plots.RegisterPlot("incoming_packet_count", [&](Plot* plot) { - analyzer.CreateAccumulatedPacketsGraph(webrtc::kIncomingPacket, plot); - }); - plots.RegisterPlot("outgoing_packet_count", [&](Plot* plot) { - analyzer.CreateAccumulatedPacketsGraph(webrtc::kOutgoingPacket, plot); - }); - plots.RegisterPlot("incoming_packet_rate", [&](Plot* plot) { - analyzer.CreatePacketRateGraph(webrtc::kIncomingPacket, plot); - }); - plots.RegisterPlot("outgoing_packet_rate", [&](Plot* plot) { - analyzer.CreatePacketRateGraph(webrtc::kOutgoingPacket, plot); - }); - plots.RegisterPlot("total_incoming_packet_rate", [&](Plot* plot) { - analyzer.CreateTotalPacketRateGraph(webrtc::kIncomingPacket, plot); - }); - plots.RegisterPlot("total_outgoing_packet_rate", [&](Plot* plot) { - analyzer.CreateTotalPacketRateGraph(webrtc::kOutgoingPacket, plot); - }); - plots.RegisterPlot("audio_playout", - [&](Plot* plot) { analyzer.CreatePlayoutGraph(plot); }); - - plots.RegisterPlot("neteq_set_minimum_delay", [&](Plot* plot) { - analyzer.CreateNetEqSetMinimumDelay(plot); - }); - - plots.RegisterPlot("incoming_audio_level", [&](Plot* plot) { - analyzer.CreateAudioLevelGraph(webrtc::kIncomingPacket, plot); - }); - plots.RegisterPlot("outgoing_audio_level", [&](Plot* plot) { - analyzer.CreateAudioLevelGraph(webrtc::kOutgoingPacket, plot); - }); - plots.RegisterPlot("incoming_sequence_number_delta", [&](Plot* plot) { - analyzer.CreateSequenceNumberGraph(plot); - }); - plots.RegisterPlot("incoming_delay", [&](Plot* plot) { - analyzer.CreateIncomingDelayGraph(plot); - }); - plots.RegisterPlot("incoming_loss_rate", [&](Plot* plot) { - analyzer.CreateIncomingPacketLossGraph(plot); - }); - plots.RegisterPlot("incoming_bitrate", [&](Plot* plot) { - analyzer.CreateTotalIncomingBitrateGraph(plot); - }); - plots.RegisterPlot("outgoing_bitrate", [&](Plot* plot) { - analyzer.CreateTotalOutgoingBitrateGraph( - plot, absl::GetFlag(FLAGS_show_detector_state), - absl::GetFlag(FLAGS_show_alr_state), - absl::GetFlag(FLAGS_show_link_capacity)); - }); - plots.RegisterPlot("incoming_stream_bitrate", [&](Plot* plot) { - analyzer.CreateStreamBitrateGraph(webrtc::kIncomingPacket, plot); - }); - plots.RegisterPlot("outgoing_stream_bitrate", [&](Plot* plot) { - analyzer.CreateStreamBitrateGraph(webrtc::kOutgoingPacket, plot); - }); - plots.RegisterPlot("incoming_layer_bitrate_allocation", [&](Plot* plot) { - analyzer.CreateBitrateAllocationGraph(webrtc::kIncomingPacket, plot); - }); - plots.RegisterPlot("outgoing_layer_bitrate_allocation", [&](Plot* plot) { - analyzer.CreateBitrateAllocationGraph(webrtc::kOutgoingPacket, plot); - }); - plots.RegisterPlot("simulated_receiveside_bwe", [&](Plot* plot) { - analyzer.CreateReceiveSideBweSimulationGraph(plot); - }); - plots.RegisterPlot("simulated_sendside_bwe", [&](Plot* plot) { - analyzer.CreateSendSideBweSimulationGraph(plot); - }); - plots.RegisterPlot("simulated_goog_cc", [&](Plot* plot) { - analyzer.CreateGoogCcSimulationGraph(plot); - }); - plots.RegisterPlot("outgoing_twcc_loss", [&](Plot* plot) { - analyzer.CreateOutgoingTWCCLossRateGraph(plot); - }); - plots.RegisterPlot("network_delay_feedback", [&](Plot* plot) { - analyzer.CreateNetworkDelayFeedbackGraph(plot); - }); - plots.RegisterPlot("fraction_loss_feedback", [&](Plot* plot) { - analyzer.CreateFractionLossGraph(plot); - }); - plots.RegisterPlot("incoming_timestamps", [&](Plot* plot) { - analyzer.CreateTimestampGraph(webrtc::kIncomingPacket, plot); - }); - plots.RegisterPlot("outgoing_timestamps", [&](Plot* plot) { - analyzer.CreateTimestampGraph(webrtc::kOutgoingPacket, plot); - }); - - auto GetFractionLost = [](const webrtc::rtcp::ReportBlock& block) -> float { - return static_cast(block.fraction_lost()) / 256 * 100; - }; - plots.RegisterPlot("incoming_rtcp_fraction_lost", [&](Plot* plot) { - analyzer.CreateSenderAndReceiverReportPlot( - webrtc::kIncomingPacket, GetFractionLost, - "Fraction lost (incoming RTCP)", "Loss rate (percent)", plot); - }); - plots.RegisterPlot("outgoing_rtcp_fraction_lost", [&](Plot* plot) { - analyzer.CreateSenderAndReceiverReportPlot( - webrtc::kOutgoingPacket, GetFractionLost, - "Fraction lost (outgoing RTCP)", "Loss rate (percent)", plot); - }); - auto GetCumulativeLost = [](const webrtc::rtcp::ReportBlock& block) -> float { - return block.cumulative_lost(); - }; - plots.RegisterPlot("incoming_rtcp_cumulative_lost", [&](Plot* plot) { - analyzer.CreateSenderAndReceiverReportPlot( - webrtc::kIncomingPacket, GetCumulativeLost, - "Cumulative lost packets (incoming RTCP)", "Packets", plot); - }); - plots.RegisterPlot("outgoing_rtcp_cumulative_lost", [&](Plot* plot) { - analyzer.CreateSenderAndReceiverReportPlot( - webrtc::kOutgoingPacket, GetCumulativeLost, - "Cumulative lost packets (outgoing RTCP)", "Packets", plot); - }); - - auto GetHighestSeqNumber = - [](const webrtc::rtcp::ReportBlock& block) -> float { - return block.extended_high_seq_num(); - }; - plots.RegisterPlot("incoming_rtcp_highest_seq_number", [&](Plot* plot) { - analyzer.CreateSenderAndReceiverReportPlot( - webrtc::kIncomingPacket, GetHighestSeqNumber, - "Highest sequence number (incoming RTCP)", "Sequence number", plot); - }); - plots.RegisterPlot("outgoing_rtcp_highest_seq_number", [&](Plot* plot) { - analyzer.CreateSenderAndReceiverReportPlot( - webrtc::kOutgoingPacket, GetHighestSeqNumber, - "Highest sequence number (outgoing RTCP)", "Sequence number", plot); - }); - - auto DelaySinceLastSr = [](const webrtc::rtcp::ReportBlock& block) -> float { - return static_cast(block.delay_since_last_sr()) / 65536; - }; - plots.RegisterPlot("incoming_rtcp_delay_since_last_sr", [&](Plot* plot) { - analyzer.CreateSenderAndReceiverReportPlot( - webrtc::kIncomingPacket, DelaySinceLastSr, - "Delay since last received sender report (incoming RTCP)", "Time (s)", - plot); - }); - plots.RegisterPlot("outgoing_rtcp_delay_since_last_sr", [&](Plot* plot) { - analyzer.CreateSenderAndReceiverReportPlot( - webrtc::kOutgoingPacket, DelaySinceLastSr, - "Delay since last received sender report (outgoing RTCP)", "Time (s)", - plot); - }); - - plots.RegisterPlot("pacer_delay", - [&](Plot* plot) { analyzer.CreatePacerDelayGraph(plot); }); - plots.RegisterPlot("audio_encoder_bitrate", [&](Plot* plot) { - CreateAudioEncoderTargetBitrateGraph(parsed_log, config, plot); - }); - plots.RegisterPlot("audio_encoder_frame_length", [&](Plot* plot) { - CreateAudioEncoderFrameLengthGraph(parsed_log, config, plot); - }); - plots.RegisterPlot("audio_encoder_packet_loss", [&](Plot* plot) { - CreateAudioEncoderPacketLossGraph(parsed_log, config, plot); - }); - plots.RegisterPlot("audio_encoder_fec", [&](Plot* plot) { - CreateAudioEncoderEnableFecGraph(parsed_log, config, plot); - }); - plots.RegisterPlot("audio_encoder_dtx", [&](Plot* plot) { - CreateAudioEncoderEnableDtxGraph(parsed_log, config, plot); - }); - plots.RegisterPlot("audio_encoder_num_channels", [&](Plot* plot) { - CreateAudioEncoderNumChannelsGraph(parsed_log, config, plot); - }); - - plots.RegisterPlot("ice_candidate_pair_config", [&](Plot* plot) { - analyzer.CreateIceCandidatePairConfigGraph(plot); - }); - plots.RegisterPlot("ice_connectivity_check", [&](Plot* plot) { - analyzer.CreateIceConnectivityCheckGraph(plot); - }); - plots.RegisterPlot("dtls_transport_state", [&](Plot* plot) { - analyzer.CreateDtlsTransportStateGraph(plot); - }); - plots.RegisterPlot("dtls_writable_state", [&](Plot* plot) { - analyzer.CreateDtlsWritableStateGraph(plot); - }); - std::string wav_path; bool has_generated_wav_file = false; if (!absl::GetFlag(FLAGS_wav_filename).empty()) { @@ -499,100 +211,53 @@ int main(int argc, char* argv[]) { webrtc::conversational_speech_en_wav_len); has_generated_wav_file = true; } - absl::optional neteq_stats; - plots.RegisterPlot("simulated_neteq_expand_rate", [&](Plot* plot) { - if (!neteq_stats) { - neteq_stats = webrtc::SimulateNetEq(parsed_log, config, wav_path, 48000); - } - webrtc::CreateNetEqNetworkStatsGraph( - parsed_log, config, *neteq_stats, - [](const webrtc::NetEqNetworkStatistics& stats) { - return stats.expand_rate / 16384.f; - }, - "Expand rate", plot); - }); + webrtc::EventLogAnalyzer analyzer(parsed_log, config); + analyzer.InitializeMapOfNamedGraphs(absl::GetFlag(FLAGS_show_detector_state), + absl::GetFlag(FLAGS_show_alr_state), + absl::GetFlag(FLAGS_show_link_capacity)); - plots.RegisterPlot("simulated_neteq_speech_expand_rate", [&](Plot* plot) { - if (!neteq_stats) { - neteq_stats = webrtc::SimulateNetEq(parsed_log, config, wav_path, 48000); - } - webrtc::CreateNetEqNetworkStatsGraph( - parsed_log, config, *neteq_stats, - [](const webrtc::NetEqNetworkStatistics& stats) { - return stats.speech_expand_rate / 16384.f; - }, - "Speech expand rate", plot); - }); - - plots.RegisterPlot("simulated_neteq_accelerate_rate", [&](Plot* plot) { - if (!neteq_stats) { - neteq_stats = webrtc::SimulateNetEq(parsed_log, config, wav_path, 48000); - } - webrtc::CreateNetEqNetworkStatsGraph( - parsed_log, config, *neteq_stats, - [](const webrtc::NetEqNetworkStatistics& stats) { - return stats.accelerate_rate / 16384.f; - }, - "Accelerate rate", plot); - }); - - plots.RegisterPlot("simulated_neteq_preemptive_rate", [&](Plot* plot) { - if (!neteq_stats) { - neteq_stats = webrtc::SimulateNetEq(parsed_log, config, wav_path, 48000); - } - webrtc::CreateNetEqNetworkStatsGraph( - parsed_log, config, *neteq_stats, - [](const webrtc::NetEqNetworkStatistics& stats) { - return stats.preemptive_rate / 16384.f; - }, - "Preemptive rate", plot); - }); - - plots.RegisterPlot("simulated_neteq_concealment_events", [&](Plot* plot) { - if (!neteq_stats) { - neteq_stats = webrtc::SimulateNetEq(parsed_log, config, wav_path, 48000); - } - webrtc::CreateNetEqLifetimeStatsGraph( - parsed_log, config, *neteq_stats, - [](const webrtc::NetEqLifetimeStatistics& stats) { - return static_cast(stats.concealment_events); - }, - "Concealment events", plot); - }); - - plots.RegisterPlot("simulated_neteq_preferred_buffer_size", [&](Plot* plot) { - if (!neteq_stats) { - neteq_stats = webrtc::SimulateNetEq(parsed_log, config, wav_path, 48000); - } - webrtc::CreateNetEqNetworkStatsGraph( - parsed_log, config, *neteq_stats, - [](const webrtc::NetEqNetworkStatistics& stats) { - return stats.preferred_buffer_size_ms; - }, - "Preferred buffer size (ms)", plot); - }); - - if (absl::c_find(plot_flags, "all") != plot_flags.end()) { - plots.EnableAllPlots(); - // Treated separately since it isn't registered like the other plots. - plot_flags.push_back("simulated_neteq_jitter_buffer_delay"); - } else { - bool success = plots.EnablePlotsByFlags(plot_flags, flag_aliases); - if (!success) { - return 1; - } - } + // Flag replacements + std::map> flag_aliases = { + {"default", + {"incoming_delay", "incoming_loss_rate", "incoming_bitrate", + "outgoing_bitrate", "incoming_stream_bitrate", + "outgoing_stream_bitrate", "network_delay_feedback", + "fraction_loss_feedback"}}, + {"sendside_bwe", + {"outgoing_packet_sizes", "outgoing_bitrate", "outgoing_stream_bitrate", + "simulated_sendside_bwe", "network_delay_feedback", + "fraction_loss_feedback", "outgoing_twcc_loss"}}, + {"receiveside_bwe", + {"incoming_packet_sizes", "incoming_delay", "incoming_loss_rate", + "incoming_bitrate", "incoming_stream_bitrate", + "simulated_receiveside_bwe"}}, + {"rtcp_details", + {"incoming_rtcp_fraction_lost", "outgoing_rtcp_fraction_lost", + "incoming_rtcp_cumulative_lost", "outgoing_rtcp_cumulative_lost", + "incoming_rtcp_highest_seq_number", "outgoing_rtcp_highest_seq_number", + "incoming_rtcp_delay_since_last_sr", + "outgoing_rtcp_delay_since_last_sr"}}, + {"simulated_neteq_stats", + {"simulated_neteq_jitter_buffer_delay", + "simulated_neteq_preferred_buffer_size", + "simulated_neteq_concealment_events", "simulated_neteq_preemptive_rate", + "simulated_neteq_accelerate_rate", "simulated_neteq_speech_expand_rate", + "simulated_neteq_expand_rate"}}}; if (absl::GetFlag(FLAGS_list_plots)) { std::cerr << "List of registered plots (for use with the --plot flag):" << std::endl; - for (const auto& plot : plots) { + for (const auto& plot_name : analyzer.GetGraphNames()) { // TODO(terelius): Also print a help text. - std::cerr << " " << plot.label << std::endl; + std::cerr << " " << plot_name; } - // The following flag doesn't fit the model used for the other plots. - std::cerr << "simulated_neteq_jitter_buffer_delay" << std::endl; + // The following flags don't fit the model used for the other plots. + for (const auto& plot_name : flag_aliases["simulated_neteq_stats"]) { + std::cerr << " " << plot_name; + } + std::cerr << std::endl; + std::cerr << "List of plot aliases (for use with the --plot flag):" << std::endl; std::cerr << " all = every registered plot" << std::endl; @@ -605,17 +270,134 @@ int main(int argc, char* argv[]) { } return 0; } + if (args.size() != 2) { // Print usage information. std::cerr << absl::ProgramUsageMessage(); return 1; } - for (const auto& plot : plots) { - if (plot.enabled) { - Plot* output = collection.AppendNewPlot(plot.label); - plot.plot_func(output); + // Select which plots to output + std::vector plot_flags = + StrSplit(absl::GetFlag(FLAGS_plot), ","); + std::vector plot_names; + const std::vector known_analyzer_plots = + analyzer.GetGraphNames(); + const std::vector known_neteq_plots = + flag_aliases["simulated_neteq_stats"]; + std::vector all_known_plots = known_analyzer_plots; + all_known_plots.insert(all_known_plots.end(), known_neteq_plots.begin(), + known_neteq_plots.end()); + for (const std::string& flag : plot_flags) { + if (flag == "all") { + plot_names = all_known_plots; + break; } + auto alias_it = flag_aliases.find(flag); + if (alias_it != flag_aliases.end()) { + for (std::string& replacement : alias_it->second) { + if (!KnownPlotName(replacement, all_known_plots)) { + std::cerr << "Unknown plot name \"" << replacement << "\"" + << std::endl; + return 1; + } + plot_names.push_back(replacement); + } + } else { + plot_names.push_back(flag); + if (!KnownPlotName(flag, all_known_plots)) { + std::cerr << "Unknown plot name \"" << flag << "\"" << std::endl; + return 1; + } + } + } + + webrtc::PlotCollection collection; + analyzer.CreateGraphsByName(plot_names, &collection); + + // The simulated neteq charts are treated separately because they have a + // different behavior compared to all other plots. In particular, the neteq + // plots + // * cache the simulation results between different plots + // * open and read files + // * dont have a 1-to-1 mapping between IDs and charts. + absl::optional neteq_stats; + if (absl::c_find(plot_names, "simulated_neteq_expand_rate") != + plot_names.end()) { + if (!neteq_stats) { + neteq_stats = webrtc::SimulateNetEq(parsed_log, config, wav_path, 48000); + } + webrtc::CreateNetEqNetworkStatsGraph( + parsed_log, config, *neteq_stats, + [](const webrtc::NetEqNetworkStatistics& stats) { + return stats.expand_rate / 16384.f; + }, + "Expand rate", collection.AppendNewPlot("simulated_neteq_expand_rate")); + } + if (absl::c_find(plot_names, "simulated_neteq_speech_expand_rate") != + plot_names.end()) { + if (!neteq_stats) { + neteq_stats = webrtc::SimulateNetEq(parsed_log, config, wav_path, 48000); + } + webrtc::CreateNetEqNetworkStatsGraph( + parsed_log, config, *neteq_stats, + [](const webrtc::NetEqNetworkStatistics& stats) { + return stats.speech_expand_rate / 16384.f; + }, + "Speech expand rate", + collection.AppendNewPlot("simulated_neteq_speech_expand_rate")); + } + if (absl::c_find(plot_names, "simulated_neteq_accelerate_rate") != + plot_names.end()) { + if (!neteq_stats) { + neteq_stats = webrtc::SimulateNetEq(parsed_log, config, wav_path, 48000); + } + webrtc::CreateNetEqNetworkStatsGraph( + parsed_log, config, *neteq_stats, + [](const webrtc::NetEqNetworkStatistics& stats) { + return stats.accelerate_rate / 16384.f; + }, + "Accelerate rate", + collection.AppendNewPlot("simulated_neteq_accelerate_rate")); + } + if (absl::c_find(plot_names, "simulated_neteq_preemptive_rate") != + plot_names.end()) { + if (!neteq_stats) { + neteq_stats = webrtc::SimulateNetEq(parsed_log, config, wav_path, 48000); + } + webrtc::CreateNetEqNetworkStatsGraph( + parsed_log, config, *neteq_stats, + [](const webrtc::NetEqNetworkStatistics& stats) { + return stats.preemptive_rate / 16384.f; + }, + "Preemptive rate", + collection.AppendNewPlot("simulated_neteq_preemptive_rate")); + } + if (absl::c_find(plot_names, "simulated_neteq_concealment_events") != + plot_names.end()) { + if (!neteq_stats) { + neteq_stats = webrtc::SimulateNetEq(parsed_log, config, wav_path, 48000); + } + webrtc::CreateNetEqLifetimeStatsGraph( + parsed_log, config, *neteq_stats, + [](const webrtc::NetEqLifetimeStatistics& stats) { + return static_cast(stats.concealment_events); + }, + "Concealment events", + collection.AppendNewPlot("simulated_neteq_concealment_events")); + } + if (absl::c_find(plot_names, "simulated_neteq_preferred_buffer_size") != + plot_names.end()) { + if (!neteq_stats) { + neteq_stats = webrtc::SimulateNetEq(parsed_log, config, wav_path, 48000); + } + webrtc::CreateNetEqNetworkStatsGraph( + parsed_log, config, *neteq_stats, + [](const webrtc::NetEqNetworkStatistics& stats) { + return stats.preferred_buffer_size_ms; + }, + "Preferred buffer size (ms)", + collection.AppendNewPlot("simulated_neteq_preferred_buffer_size")); } // The model we use for registering plots assumes that the each plot label @@ -623,19 +405,20 @@ int main(int argc, char* argv[]) { // simulated_neteq_jitter_buffer_delay plot doesn't fit this model since it // creates multiple plots, and would need some state kept between the lambda // calls. - if (absl::c_find(plot_flags, "simulated_neteq_jitter_buffer_delay") != - plot_flags.end()) { + if (absl::c_find(plot_names, "simulated_neteq_jitter_buffer_delay") != + plot_names.end()) { if (!neteq_stats) { neteq_stats = webrtc::SimulateNetEq(parsed_log, config, wav_path, 48000); } - for (webrtc::NetEqStatsGetterMap::const_iterator it = neteq_stats->cbegin(); - it != neteq_stats->cend(); ++it) { - webrtc::CreateAudioJitterBufferGraph(parsed_log, config, it->first, - it->second.get(), - collection.AppendNewPlot()); + for (auto it = neteq_stats->cbegin(); it != neteq_stats->cend(); ++it) { + webrtc::CreateAudioJitterBufferGraph( + parsed_log, config, it->first, it->second.get(), + collection.AppendNewPlot("simulated_neteq_jitter_buffer_delay")); } } + collection.SetCallTimeToUtcOffsetMs(config.CallTimeToUtcOffsetMs()); + if (absl::GetFlag(FLAGS_protobuf_output)) { webrtc::analytics::ChartCollection proto_charts; collection.ExportProtobuf(&proto_charts);