1 /*
2  *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 #include "test/pc/e2e/network_quality_metrics_reporter.h"
11 
12 #include <utility>
13 
14 #include "api/stats_types.h"
15 #include "rtc_base/event.h"
16 #include "system_wrappers/include/field_trial.h"
17 #include "test/testsupport/perf_test.h"
18 
19 namespace webrtc {
20 namespace webrtc_pc_e2e {
21 namespace {
22 
23 constexpr int kStatsWaitTimeoutMs = 1000;
24 
25 // Field trial which controls whether to report standard-compliant bytes
26 // sent/received per stream.  If enabled, padding and headers are not included
27 // in bytes sent or received.
28 constexpr char kUseStandardBytesStats[] = "WebRTC-UseStandardBytesStats";
29 }
30 
Start(absl::string_view test_case_name)31 void NetworkQualityMetricsReporter::Start(absl::string_view test_case_name) {
32   test_case_name_ = std::string(test_case_name);
33   // Check that network stats are clean before test execution.
34   EmulatedNetworkStats alice_stats = PopulateStats(alice_network_);
35   RTC_CHECK_EQ(alice_stats.packets_sent, 0);
36   RTC_CHECK_EQ(alice_stats.packets_received, 0);
37   EmulatedNetworkStats bob_stats = PopulateStats(bob_network_);
38   RTC_CHECK_EQ(bob_stats.packets_sent, 0);
39   RTC_CHECK_EQ(bob_stats.packets_received, 0);
40 }
41 
OnStatsReports(const std::string & pc_label,const StatsReports & reports)42 void NetworkQualityMetricsReporter::OnStatsReports(
43     const std::string& pc_label,
44     const StatsReports& reports) {
45   rtc::CritScope cs(&lock_);
46   int64_t payload_bytes_received = 0;
47   int64_t payload_bytes_sent = 0;
48   for (const StatsReport* report : reports) {
49     if (report->type() == StatsReport::kStatsReportTypeSsrc) {
50       const auto* received =
51           report->FindValue(StatsReport::kStatsValueNameBytesReceived);
52       if (received) {
53         payload_bytes_received += received->int64_val();
54       }
55       const auto* sent =
56           report->FindValue(StatsReport::kStatsValueNameBytesSent);
57       if (sent) {
58         payload_bytes_sent += sent->int64_val();
59       }
60     }
61   }
62   PCStats& stats = pc_stats_[pc_label];
63   stats.payload_bytes_received = payload_bytes_received;
64   stats.payload_bytes_sent = payload_bytes_sent;
65 }
66 
StopAndReportResults()67 void NetworkQualityMetricsReporter::StopAndReportResults() {
68   EmulatedNetworkStats alice_stats = PopulateStats(alice_network_);
69   EmulatedNetworkStats bob_stats = PopulateStats(bob_network_);
70   ReportStats("alice", alice_stats,
71               alice_stats.packets_sent - bob_stats.packets_received);
72   ReportStats("bob", bob_stats,
73               bob_stats.packets_sent - alice_stats.packets_received);
74 
75   if (!webrtc::field_trial::IsEnabled(kUseStandardBytesStats)) {
76     RTC_LOG(LS_ERROR)
77         << "Non-standard GetStats; \"payload\" counts include RTP headers";
78   }
79 
80   rtc::CritScope cs(&lock_);
81   for (const auto& pair : pc_stats_) {
82     ReportPCStats(pair.first, pair.second);
83   }
84 }
85 
PopulateStats(EmulatedNetworkManagerInterface * network)86 EmulatedNetworkStats NetworkQualityMetricsReporter::PopulateStats(
87     EmulatedNetworkManagerInterface* network) {
88   rtc::Event wait;
89   EmulatedNetworkStats stats;
90   network->GetStats([&](const EmulatedNetworkStats& s) {
91     stats = s;
92     wait.Set();
93   });
94   bool stats_received = wait.Wait(kStatsWaitTimeoutMs);
95   RTC_CHECK(stats_received);
96   return stats;
97 }
98 
ReportStats(const std::string & network_label,const EmulatedNetworkStats & stats,int64_t packet_loss)99 void NetworkQualityMetricsReporter::ReportStats(
100     const std::string& network_label,
101     const EmulatedNetworkStats& stats,
102     int64_t packet_loss) {
103   ReportResult("bytes_sent", network_label, stats.bytes_sent.bytes(),
104                "sizeInBytes");
105   ReportResult("packets_sent", network_label, stats.packets_sent, "unitless");
106   ReportResult(
107       "average_send_rate", network_label,
108       stats.packets_sent >= 2 ? stats.AverageSendRate().bytes_per_sec() : 0,
109       "bytesPerSecond");
110   ReportResult("bytes_dropped", network_label, stats.bytes_dropped.bytes(),
111                "sizeInBytes");
112   ReportResult("packets_dropped", network_label, stats.packets_dropped,
113                "unitless");
114   ReportResult("bytes_received", network_label, stats.bytes_received.bytes(),
115                "sizeInBytes");
116   ReportResult("packets_received", network_label, stats.packets_received,
117                "unitless");
118   ReportResult("average_receive_rate", network_label,
119                stats.packets_received >= 2
120                    ? stats.AverageReceiveRate().bytes_per_sec()
121                    : 0,
122                "bytesPerSecond");
123   ReportResult("sent_packets_loss", network_label, packet_loss, "unitless");
124 }
125 
ReportPCStats(const std::string & pc_label,const PCStats & stats)126 void NetworkQualityMetricsReporter::ReportPCStats(const std::string& pc_label,
127                                                   const PCStats& stats) {
128   ReportResult("payload_bytes_received", pc_label, stats.payload_bytes_received,
129                "sizeInBytes");
130   ReportResult("payload_bytes_sent", pc_label, stats.payload_bytes_sent,
131                "sizeInBytes");
132 }
133 
ReportResult(const std::string & metric_name,const std::string & network_label,const double value,const std::string & unit) const134 void NetworkQualityMetricsReporter::ReportResult(
135     const std::string& metric_name,
136     const std::string& network_label,
137     const double value,
138     const std::string& unit) const {
139   test::PrintResult(metric_name, /*modifier=*/"",
140                     GetTestCaseName(network_label), value, unit,
141                     /*important=*/false);
142 }
143 
GetTestCaseName(const std::string & network_label) const144 std::string NetworkQualityMetricsReporter::GetTestCaseName(
145     const std::string& network_label) const {
146   return test_case_name_ + "/" + network_label;
147 }
148 
149 }  // namespace webrtc_pc_e2e
150 }  // namespace webrtc
151