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