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/rtc_stats.h"
15 #include "api/stats/rtcstats_objects.h"
16 #include "rtc_base/event.h"
17 #include "system_wrappers/include/field_trial.h"
18 #include "test/testsupport/perf_test.h"
19
20 namespace webrtc {
21 namespace webrtc_pc_e2e {
22 namespace {
23
24 constexpr int kStatsWaitTimeoutMs = 1000;
25
26 // Field trial which controls whether to report standard-compliant bytes
27 // sent/received per stream. If enabled, padding and headers are not included
28 // in bytes sent or received.
29 constexpr char kUseStandardBytesStats[] = "WebRTC-UseStandardBytesStats";
30 }
31
Start(absl::string_view test_case_name,const TrackIdStreamInfoMap *)32 void NetworkQualityMetricsReporter::Start(
33 absl::string_view test_case_name,
34 const TrackIdStreamInfoMap* /*reporter_helper*/) {
35 test_case_name_ = std::string(test_case_name);
36 // Check that network stats are clean before test execution.
37 EmulatedNetworkStats alice_stats = PopulateStats(alice_network_);
38 RTC_CHECK_EQ(alice_stats.packets_sent, 0);
39 RTC_CHECK_EQ(alice_stats.PacketsReceived(), 0);
40 EmulatedNetworkStats bob_stats = PopulateStats(bob_network_);
41 RTC_CHECK_EQ(bob_stats.packets_sent, 0);
42 RTC_CHECK_EQ(bob_stats.PacketsReceived(), 0);
43 }
44
OnStatsReports(absl::string_view pc_label,const rtc::scoped_refptr<const RTCStatsReport> & report)45 void NetworkQualityMetricsReporter::OnStatsReports(
46 absl::string_view pc_label,
47 const rtc::scoped_refptr<const RTCStatsReport>& report) {
48 DataSize payload_received = DataSize::Zero();
49 DataSize payload_sent = DataSize::Zero();
50
51 auto inbound_stats = report->GetStatsOfType<RTCInboundRTPStreamStats>();
52 for (const auto& stat : inbound_stats) {
53 payload_received +=
54 DataSize::Bytes(stat->bytes_received.ValueOrDefault(0ul) +
55 stat->header_bytes_received.ValueOrDefault(0ul));
56 }
57
58 auto outbound_stats = report->GetStatsOfType<RTCOutboundRTPStreamStats>();
59 for (const auto& stat : outbound_stats) {
60 payload_sent +=
61 DataSize::Bytes(stat->bytes_sent.ValueOrDefault(0ul) +
62 stat->header_bytes_sent.ValueOrDefault(0ul));
63 }
64
65 MutexLock lock(&lock_);
66 PCStats& stats = pc_stats_[std::string(pc_label)];
67 stats.payload_received = payload_received;
68 stats.payload_sent = payload_sent;
69 }
70
StopAndReportResults()71 void NetworkQualityMetricsReporter::StopAndReportResults() {
72 EmulatedNetworkStats alice_stats = PopulateStats(alice_network_);
73 EmulatedNetworkStats bob_stats = PopulateStats(bob_network_);
74 ReportStats("alice", alice_stats,
75 alice_stats.packets_sent - bob_stats.PacketsReceived());
76 ReportStats("bob", bob_stats,
77 bob_stats.packets_sent - alice_stats.PacketsReceived());
78
79 if (!webrtc::field_trial::IsEnabled(kUseStandardBytesStats)) {
80 RTC_LOG(LS_ERROR)
81 << "Non-standard GetStats; \"payload\" counts include RTP headers";
82 }
83
84 MutexLock lock(&lock_);
85 for (const auto& pair : pc_stats_) {
86 ReportPCStats(pair.first, pair.second);
87 }
88 }
89
PopulateStats(EmulatedNetworkManagerInterface * network)90 EmulatedNetworkStats NetworkQualityMetricsReporter::PopulateStats(
91 EmulatedNetworkManagerInterface* network) {
92 rtc::Event wait;
93 EmulatedNetworkStats stats;
94 network->GetStats([&](const EmulatedNetworkStats& s) {
95 stats = s;
96 wait.Set();
97 });
98 bool stats_received = wait.Wait(kStatsWaitTimeoutMs);
99 RTC_CHECK(stats_received);
100 return stats;
101 }
102
ReportStats(const std::string & network_label,const EmulatedNetworkStats & stats,int64_t packet_loss)103 void NetworkQualityMetricsReporter::ReportStats(
104 const std::string& network_label,
105 const EmulatedNetworkStats& stats,
106 int64_t packet_loss) {
107 ReportResult("bytes_sent", network_label, stats.bytes_sent.bytes(),
108 "sizeInBytes");
109 ReportResult("packets_sent", network_label, stats.packets_sent, "unitless");
110 ReportResult(
111 "average_send_rate", network_label,
112 stats.packets_sent >= 2 ? stats.AverageSendRate().bytes_per_sec() : 0,
113 "bytesPerSecond");
114 ReportResult("bytes_dropped", network_label, stats.BytesDropped().bytes(),
115 "sizeInBytes");
116 ReportResult("packets_dropped", network_label, stats.PacketsDropped(),
117 "unitless");
118 ReportResult("bytes_received", network_label, stats.BytesReceived().bytes(),
119 "sizeInBytes");
120 ReportResult("packets_received", network_label, stats.PacketsReceived(),
121 "unitless");
122 ReportResult("average_receive_rate", network_label,
123 stats.PacketsReceived() >= 2
124 ? stats.AverageReceiveRate().bytes_per_sec()
125 : 0,
126 "bytesPerSecond");
127 ReportResult("sent_packets_loss", network_label, packet_loss, "unitless");
128 }
129
ReportPCStats(const std::string & pc_label,const PCStats & stats)130 void NetworkQualityMetricsReporter::ReportPCStats(const std::string& pc_label,
131 const PCStats& stats) {
132 ReportResult("payload_bytes_received", pc_label,
133 stats.payload_received.bytes(), "sizeInBytes");
134 ReportResult("payload_bytes_sent", pc_label, stats.payload_sent.bytes(),
135 "sizeInBytes");
136 }
137
ReportResult(const std::string & metric_name,const std::string & network_label,const double value,const std::string & unit) const138 void NetworkQualityMetricsReporter::ReportResult(
139 const std::string& metric_name,
140 const std::string& network_label,
141 const double value,
142 const std::string& unit) const {
143 test::PrintResult(metric_name, /*modifier=*/"",
144 GetTestCaseName(network_label), value, unit,
145 /*important=*/false);
146 }
147
GetTestCaseName(const std::string & network_label) const148 std::string NetworkQualityMetricsReporter::GetTestCaseName(
149 const std::string& network_label) const {
150 return test_case_name_ + "/" + network_label;
151 }
152
153 } // namespace webrtc_pc_e2e
154 } // namespace webrtc
155