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