text: /*
   *  Copyright (c) 2019 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 "test/pc/e2e/network_quality_metrics_reporter.h"
  
  #include <utility>
  
  #include "api/stats/rtc_stats.h"
  #include "api/stats/rtcstats_objects.h"
  #include "rtc_base/event.h"
  #include "system_wrappers/include/field_trial.h"
  #include "test/testsupport/perf_test.h"
  
  namespace webrtc {
  namespace webrtc_pc_e2e {
  namespace {
  
  constexpr int kStatsWaitTimeoutMs = 1000;
  
  // Field trial which controls whether to report standard-compliant bytes
  // sent/received per stream.  If enabled, padding and headers are not included
  // in bytes sent or received.
  constexpr char kUseStandardBytesStats[] = "WebRTC-UseStandardBytesStats";
  }
  
  void NetworkQualityMetricsReporter::Start(
      absl::string_view test_case_name,
      const TrackIdStreamInfoMap* /*reporter_helper*/) {
    test_case_name_ = std::string(test_case_name);
    // Check that network stats are clean before test execution.
    std::unique_ptr<EmulatedNetworkStats> alice_stats =
        PopulateStats(alice_network_);
    RTC_CHECK_EQ(alice_stats->PacketsSent(), 0);
    RTC_CHECK_EQ(alice_stats->PacketsReceived(), 0);
    std::unique_ptr<EmulatedNetworkStats> bob_stats = PopulateStats(bob_network_);
    RTC_CHECK_EQ(bob_stats->PacketsSent(), 0);
    RTC_CHECK_EQ(bob_stats->PacketsReceived(), 0);
  }
  
  void NetworkQualityMetricsReporter::OnStatsReports(
      absl::string_view pc_label,
      const rtc::scoped_refptr<const RTCStatsReport>& report) {
    DataSize payload_received = DataSize::Zero();
    DataSize payload_sent = DataSize::Zero();
  
    auto inbound_stats = report->GetStatsOfType<RTCInboundRTPStreamStats>();
    for (const auto& stat : inbound_stats) {
      payload_received +=
          DataSize::Bytes(stat->bytes_received.ValueOrDefault(0ul) +
                          stat->header_bytes_received.ValueOrDefault(0ul));
    }
  
    auto outbound_stats = report->GetStatsOfType<RTCOutboundRTPStreamStats>();
    for (const auto& stat : outbound_stats) {
      payload_sent +=
          DataSize::Bytes(stat->bytes_sent.ValueOrDefault(0ul) +
                          stat->header_bytes_sent.ValueOrDefault(0ul));
    }
  
    MutexLock lock(&lock_);
    PCStats& stats = pc_stats_[std::string(pc_label)];
    stats.payload_received = payload_received;
    stats.payload_sent = payload_sent;
  }
  
  void NetworkQualityMetricsReporter::StopAndReportResults() {
    std::unique_ptr<EmulatedNetworkStats> alice_stats =
        PopulateStats(alice_network_);
    std::unique_ptr<EmulatedNetworkStats> bob_stats = PopulateStats(bob_network_);
    int64_t alice_packets_loss =
        alice_stats->PacketsSent() - bob_stats->PacketsReceived();
    int64_t bob_packets_loss =
        bob_stats->PacketsSent() - alice_stats->PacketsReceived();
    ReportStats("alice", std::move(alice_stats), alice_packets_loss);
    ReportStats("bob", std::move(bob_stats), bob_packets_loss);
  
    if (!webrtc::field_trial::IsEnabled(kUseStandardBytesStats)) {
      RTC_LOG(LS_ERROR)
          << "Non-standard GetStats; \"payload\" counts include RTP headers";
    }
  
    MutexLock lock(&lock_);
    for (const auto& pair : pc_stats_) {
      ReportPCStats(pair.first, pair.second);
    }
  }
  
  std::unique_ptr<EmulatedNetworkStats>
  NetworkQualityMetricsReporter::PopulateStats(
      EmulatedNetworkManagerInterface* network) {
    rtc::Event wait;
    std::unique_ptr<EmulatedNetworkStats> stats;
    network->GetStats([&](std::unique_ptr<EmulatedNetworkStats> s) {
      stats = std::move(s);
      wait.Set();
    });
    bool stats_received = wait.Wait(kStatsWaitTimeoutMs);
    RTC_CHECK(stats_received);
    return stats;
  }
  
  void NetworkQualityMetricsReporter::ReportStats(
      const std::string& network_label,
      std::unique_ptr<EmulatedNetworkStats> stats,
      int64_t packet_loss) {
    ReportResult("bytes_sent", network_label, stats->BytesSent().bytes(),
                 "sizeInBytes");
    ReportResult("packets_sent", network_label, stats->PacketsSent(), "unitless");
    ReportResult(
        "average_send_rate", network_label,
        stats->PacketsSent() >= 2 ? stats->AverageSendRate().bytes_per_sec() : 0,
        "bytesPerSecond");
    ReportResult("bytes_dropped", network_label, stats->BytesDropped().bytes(),
                 "sizeInBytes");
    ReportResult("packets_dropped", network_label, stats->PacketsDropped(),
                 "unitless");
    ReportResult("bytes_received", network_label, stats->BytesReceived().bytes(),
                 "sizeInBytes");
    ReportResult("packets_received", network_label, stats->PacketsReceived(),
                 "unitless");
    ReportResult("average_receive_rate", network_label,
                 stats->PacketsReceived() >= 2
                     ? stats->AverageReceiveRate().bytes_per_sec()
                     : 0,
                 "bytesPerSecond");
    ReportResult("sent_packets_loss", network_label, packet_loss, "unitless");
  }
  
  void NetworkQualityMetricsReporter::ReportPCStats(const std::string& pc_label,
                                                    const PCStats& stats) {
    ReportResult("payload_bytes_received", pc_label,
                 stats.payload_received.bytes(), "sizeInBytes");
    ReportResult("payload_bytes_sent", pc_label, stats.payload_sent.bytes(),
                 "sizeInBytes");
  }
  
  void NetworkQualityMetricsReporter::ReportResult(
      const std::string& metric_name,
      const std::string& network_label,
      const double value,
      const std::string& unit) const {
    test::PrintResult(metric_name, /*modifier=*/"",
                      GetTestCaseName(network_label), value, unit,
                      /*important=*/false);
  }
  
  std::string NetworkQualityMetricsReporter::GetTestCaseName(
      const std::string& network_label) const {
    return test_case_name_ + "/" + network_label;
  }
  
  }  // namespace webrtc_pc_e2e
  }  // namespace webrtc
  