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 "api/stats/rtc_stats.h"
14 #include "api/stats/rtcstats_objects.h"
15 #include "api/units/data_rate.h"
16 #include "api/units/time_delta.h"
17 #include "api/units/timestamp.h"
18
19 namespace webrtc {
20 namespace webrtc_pc_e2e {
21
Start(absl::string_view test_case_name,const TrackIdStreamInfoMap *)22 void VideoQualityMetricsReporter::Start(
23 absl::string_view test_case_name,
24 const TrackIdStreamInfoMap* /*reporter_helper*/) {
25 test_case_name_ = std::string(test_case_name);
26 start_time_ = Now();
27 }
28
OnStatsReports(absl::string_view pc_label,const rtc::scoped_refptr<const RTCStatsReport> & report)29 void VideoQualityMetricsReporter::OnStatsReports(
30 absl::string_view pc_label,
31 const rtc::scoped_refptr<const RTCStatsReport>& report) {
32 RTC_CHECK(start_time_)
33 << "Please invoke Start(...) method before calling OnStatsReports(...)";
34
35 auto transport_stats = report->GetStatsOfType<RTCTransportStats>();
36 if (transport_stats.size() == 0u ||
37 !transport_stats[0]->selected_candidate_pair_id.is_defined()) {
38 return;
39 }
40 RTC_DCHECK_EQ(transport_stats.size(), 1);
41 std::string selected_ice_id =
42 transport_stats[0]->selected_candidate_pair_id.ValueToString();
43 // Use the selected ICE candidate pair ID to get the appropriate ICE stats.
44 const RTCIceCandidatePairStats ice_candidate_pair_stats =
45 report->Get(selected_ice_id)->cast_to<const RTCIceCandidatePairStats>();
46
47 auto outbound_rtp_stats = report->GetStatsOfType<RTCOutboundRTPStreamStats>();
48 StatsSample sample;
49 for (auto& s : outbound_rtp_stats) {
50 if (!s->media_type.is_defined()) {
51 continue;
52 }
53 if (!(*s->media_type == RTCMediaStreamTrackKind::kVideo)) {
54 continue;
55 }
56 if (s->timestamp_us() > sample.sample_time.us()) {
57 sample.sample_time = Timestamp::Micros(s->timestamp_us());
58 }
59 sample.retransmitted_bytes_sent +=
60 DataSize::Bytes(s->retransmitted_bytes_sent.ValueOrDefault(0ul));
61 sample.bytes_sent += DataSize::Bytes(s->bytes_sent.ValueOrDefault(0ul));
62 sample.header_bytes_sent +=
63 DataSize::Bytes(s->header_bytes_sent.ValueOrDefault(0ul));
64 }
65
66 MutexLock lock(&video_bwe_stats_lock_);
67 VideoBweStats& video_bwe_stats = video_bwe_stats_[std::string(pc_label)];
68 if (ice_candidate_pair_stats.available_outgoing_bitrate.is_defined()) {
69 video_bwe_stats.available_send_bandwidth.AddSample(
70 DataRate::BitsPerSec(
71 *ice_candidate_pair_stats.available_outgoing_bitrate)
72 .bytes_per_sec());
73 }
74
75 StatsSample prev_sample = last_stats_sample_[std::string(pc_label)];
76 if (prev_sample.sample_time.IsZero()) {
77 prev_sample.sample_time = start_time_.value();
78 }
79 last_stats_sample_[std::string(pc_label)] = sample;
80
81 TimeDelta time_between_samples = sample.sample_time - prev_sample.sample_time;
82 if (time_between_samples.IsZero()) {
83 return;
84 }
85
86 DataRate retransmission_bitrate =
87 (sample.retransmitted_bytes_sent - prev_sample.retransmitted_bytes_sent) /
88 time_between_samples;
89 video_bwe_stats.retransmission_bitrate.AddSample(
90 retransmission_bitrate.bytes_per_sec());
91 DataRate transmission_bitrate =
92 (sample.bytes_sent + sample.header_bytes_sent - prev_sample.bytes_sent -
93 prev_sample.header_bytes_sent) /
94 time_between_samples;
95 video_bwe_stats.transmission_bitrate.AddSample(
96 transmission_bitrate.bytes_per_sec());
97 }
98
StopAndReportResults()99 void VideoQualityMetricsReporter::StopAndReportResults() {
100 MutexLock video_bwemutex_(&video_bwe_stats_lock_);
101 for (const auto& item : video_bwe_stats_) {
102 ReportVideoBweResults(GetTestCaseName(item.first), item.second);
103 }
104 }
105
GetTestCaseName(const std::string & stream_label) const106 std::string VideoQualityMetricsReporter::GetTestCaseName(
107 const std::string& stream_label) const {
108 return test_case_name_ + "/" + stream_label;
109 }
110
ReportVideoBweResults(const std::string & test_case_name,const VideoBweStats & video_bwe_stats)111 void VideoQualityMetricsReporter::ReportVideoBweResults(
112 const std::string& test_case_name,
113 const VideoBweStats& video_bwe_stats) {
114 ReportResult("available_send_bandwidth", test_case_name,
115 video_bwe_stats.available_send_bandwidth, "bytesPerSecond");
116 ReportResult("transmission_bitrate", test_case_name,
117 video_bwe_stats.transmission_bitrate, "bytesPerSecond");
118 ReportResult("retransmission_bitrate", test_case_name,
119 video_bwe_stats.retransmission_bitrate, "bytesPerSecond");
120 }
121
ReportResult(const std::string & metric_name,const std::string & test_case_name,const SamplesStatsCounter & counter,const std::string & unit,webrtc::test::ImproveDirection improve_direction)122 void VideoQualityMetricsReporter::ReportResult(
123 const std::string& metric_name,
124 const std::string& test_case_name,
125 const SamplesStatsCounter& counter,
126 const std::string& unit,
127 webrtc::test::ImproveDirection improve_direction) {
128 test::PrintResult(metric_name, /*modifier=*/"", test_case_name, counter, unit,
129 /*important=*/false, improve_direction);
130 }
131
132 } // namespace webrtc_pc_e2e
133 } // namespace webrtc
134