1 /*
2 * Copyright (c) 2020 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
11 #include "test/pc/e2e/analyzer/video/video_quality_metrics_reporter.h"
12
13 #include <map>
14 #include <string>
15
16 #include "api/stats/rtc_stats.h"
17 #include "api/stats/rtcstats_objects.h"
18 #include "api/test/metrics/metric.h"
19 #include "api/units/data_rate.h"
20 #include "api/units/time_delta.h"
21 #include "api/units/timestamp.h"
22 #include "rtc_base/checks.h"
23 #include "test/pc/e2e/metric_metadata_keys.h"
24
25 namespace webrtc {
26 namespace webrtc_pc_e2e {
27 namespace {
28
29 using ::webrtc::test::ImprovementDirection;
30 using ::webrtc::test::Unit;
31 using ::webrtc::webrtc_pc_e2e::MetricMetadataKey;
32
BytesPerSecondToKbps(const SamplesStatsCounter & counter)33 SamplesStatsCounter BytesPerSecondToKbps(const SamplesStatsCounter& counter) {
34 return counter * 0.008;
35 }
36
37 } // namespace
38
VideoQualityMetricsReporter(Clock * const clock,test::MetricsLogger * const metrics_logger)39 VideoQualityMetricsReporter::VideoQualityMetricsReporter(
40 Clock* const clock,
41 test::MetricsLogger* const metrics_logger)
42 : clock_(clock), metrics_logger_(metrics_logger) {
43 RTC_CHECK(metrics_logger_);
44 }
45
Start(absl::string_view test_case_name,const TrackIdStreamInfoMap *)46 void VideoQualityMetricsReporter::Start(
47 absl::string_view test_case_name,
48 const TrackIdStreamInfoMap* /*reporter_helper*/) {
49 test_case_name_ = std::string(test_case_name);
50 start_time_ = Now();
51 }
52
OnStatsReports(absl::string_view pc_label,const rtc::scoped_refptr<const RTCStatsReport> & report)53 void VideoQualityMetricsReporter::OnStatsReports(
54 absl::string_view pc_label,
55 const rtc::scoped_refptr<const RTCStatsReport>& report) {
56 RTC_CHECK(start_time_)
57 << "Please invoke Start(...) method before calling OnStatsReports(...)";
58
59 auto transport_stats = report->GetStatsOfType<RTCTransportStats>();
60 if (transport_stats.size() == 0u ||
61 !transport_stats[0]->selected_candidate_pair_id.is_defined()) {
62 return;
63 }
64 RTC_DCHECK_EQ(transport_stats.size(), 1);
65 std::string selected_ice_id =
66 transport_stats[0]->selected_candidate_pair_id.ValueToString();
67 // Use the selected ICE candidate pair ID to get the appropriate ICE stats.
68 const RTCIceCandidatePairStats ice_candidate_pair_stats =
69 report->Get(selected_ice_id)->cast_to<const RTCIceCandidatePairStats>();
70
71 auto outbound_rtp_stats = report->GetStatsOfType<RTCOutboundRTPStreamStats>();
72 StatsSample sample;
73 for (auto& s : outbound_rtp_stats) {
74 if (!s->kind.is_defined()) {
75 continue;
76 }
77 if (!(*s->kind == RTCMediaStreamTrackKind::kVideo)) {
78 continue;
79 }
80 if (s->timestamp_us() > sample.sample_time.us()) {
81 sample.sample_time = Timestamp::Micros(s->timestamp_us());
82 }
83 sample.retransmitted_bytes_sent +=
84 DataSize::Bytes(s->retransmitted_bytes_sent.ValueOrDefault(0ul));
85 sample.bytes_sent += DataSize::Bytes(s->bytes_sent.ValueOrDefault(0ul));
86 sample.header_bytes_sent +=
87 DataSize::Bytes(s->header_bytes_sent.ValueOrDefault(0ul));
88 }
89
90 MutexLock lock(&video_bwe_stats_lock_);
91 VideoBweStats& video_bwe_stats = video_bwe_stats_[std::string(pc_label)];
92 if (ice_candidate_pair_stats.available_outgoing_bitrate.is_defined()) {
93 video_bwe_stats.available_send_bandwidth.AddSample(
94 DataRate::BitsPerSec(
95 *ice_candidate_pair_stats.available_outgoing_bitrate)
96 .bytes_per_sec());
97 }
98
99 StatsSample prev_sample = last_stats_sample_[std::string(pc_label)];
100 if (prev_sample.sample_time.IsZero()) {
101 prev_sample.sample_time = start_time_.value();
102 }
103 last_stats_sample_[std::string(pc_label)] = sample;
104
105 TimeDelta time_between_samples = sample.sample_time - prev_sample.sample_time;
106 if (time_between_samples.IsZero()) {
107 return;
108 }
109
110 DataRate retransmission_bitrate =
111 (sample.retransmitted_bytes_sent - prev_sample.retransmitted_bytes_sent) /
112 time_between_samples;
113 video_bwe_stats.retransmission_bitrate.AddSample(
114 retransmission_bitrate.bytes_per_sec());
115 DataRate transmission_bitrate =
116 (sample.bytes_sent + sample.header_bytes_sent - prev_sample.bytes_sent -
117 prev_sample.header_bytes_sent) /
118 time_between_samples;
119 video_bwe_stats.transmission_bitrate.AddSample(
120 transmission_bitrate.bytes_per_sec());
121 }
122
StopAndReportResults()123 void VideoQualityMetricsReporter::StopAndReportResults() {
124 MutexLock video_bwemutex_(&video_bwe_stats_lock_);
125 for (const auto& item : video_bwe_stats_) {
126 ReportVideoBweResults(item.first, item.second);
127 }
128 }
129
GetTestCaseName(const std::string & peer_name) const130 std::string VideoQualityMetricsReporter::GetTestCaseName(
131 const std::string& peer_name) const {
132 return test_case_name_ + "/" + peer_name;
133 }
134
ReportVideoBweResults(const std::string & peer_name,const VideoBweStats & video_bwe_stats)135 void VideoQualityMetricsReporter::ReportVideoBweResults(
136 const std::string& peer_name,
137 const VideoBweStats& video_bwe_stats) {
138 std::string test_case_name = GetTestCaseName(peer_name);
139 std::map<std::string, std::string> metric_metadata{
140 {MetricMetadataKey::kPeerMetadataKey, peer_name}};
141
142 metrics_logger_->LogMetric(
143 "available_send_bandwidth", test_case_name,
144 BytesPerSecondToKbps(video_bwe_stats.available_send_bandwidth),
145 Unit::kKilobitsPerSecond, ImprovementDirection::kNeitherIsBetter,
146 metric_metadata);
147 metrics_logger_->LogMetric(
148 "transmission_bitrate", test_case_name,
149 BytesPerSecondToKbps(video_bwe_stats.transmission_bitrate),
150 Unit::kKilobitsPerSecond, ImprovementDirection::kNeitherIsBetter,
151 metric_metadata);
152 metrics_logger_->LogMetric(
153 "retransmission_bitrate", test_case_name,
154 BytesPerSecondToKbps(video_bwe_stats.retransmission_bitrate),
155 Unit::kKilobitsPerSecond, ImprovementDirection::kNeitherIsBetter,
156 metric_metadata);
157 }
158
159 } // namespace webrtc_pc_e2e
160 } // namespace webrtc
161