| /* |
| * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| #include "test/pc/e2e/network_quality_metrics_reporter.h" |
| |
| #include <utility> |
| |
| #include "api/stats/rtc_stats.h" |
| #include "api/stats/rtcstats_objects.h" |
| #include "api/test/metrics/metric.h" |
| #include "rtc_base/checks.h" |
| #include "rtc_base/event.h" |
| #include "system_wrappers/include/field_trial.h" |
| |
| namespace webrtc { |
| namespace webrtc_pc_e2e { |
| namespace { |
| |
| using ::webrtc::test::ImprovementDirection; |
| using ::webrtc::test::Unit; |
| |
| constexpr TimeDelta kStatsWaitTimeout = TimeDelta::Seconds(1); |
| |
| // Field trial which controls whether to report standard-compliant bytes |
| // sent/received per stream. If enabled, padding and headers are not included |
| // in bytes sent or received. |
| constexpr char kUseStandardBytesStats[] = "WebRTC-UseStandardBytesStats"; |
| |
| } // namespace |
| |
| NetworkQualityMetricsReporter::NetworkQualityMetricsReporter( |
| EmulatedNetworkManagerInterface* alice_network, |
| EmulatedNetworkManagerInterface* bob_network, |
| test::MetricsLogger* metrics_logger) |
| : alice_network_(alice_network), |
| bob_network_(bob_network), |
| metrics_logger_(metrics_logger) { |
| RTC_CHECK(metrics_logger_); |
| } |
| |
| NetworkQualityMetricsReporter::NetworkQualityMetricsReporter( |
| absl::string_view alice_network_label, |
| EmulatedNetworkManagerInterface* alice_network, |
| absl::string_view bob_network_label, |
| EmulatedNetworkManagerInterface* bob_network, |
| test::MetricsLogger* metrics_logger) |
| : NetworkQualityMetricsReporter(alice_network, |
| bob_network, |
| metrics_logger) { |
| alice_network_label_ = std::string(alice_network_label); |
| bob_network_label_ = std::string(bob_network_label); |
| } |
| |
| void NetworkQualityMetricsReporter::Start( |
| absl::string_view test_case_name, |
| const TrackIdStreamInfoMap* /*reporter_helper*/) { |
| test_case_name_ = std::string(test_case_name); |
| // Check that network stats are clean before test execution. |
| EmulatedNetworkStats alice_stats = PopulateStats(alice_network_); |
| RTC_CHECK_EQ(alice_stats.overall_outgoing_stats.packets_sent, 0); |
| RTC_CHECK_EQ(alice_stats.overall_incoming_stats.packets_received, 0); |
| EmulatedNetworkStats bob_stats = PopulateStats(bob_network_); |
| RTC_CHECK_EQ(bob_stats.overall_outgoing_stats.packets_sent, 0); |
| RTC_CHECK_EQ(bob_stats.overall_incoming_stats.packets_received, 0); |
| } |
| |
| void NetworkQualityMetricsReporter::OnStatsReports( |
| absl::string_view pc_label, |
| const rtc::scoped_refptr<const RTCStatsReport>& report) { |
| DataSize payload_received = DataSize::Zero(); |
| DataSize payload_sent = DataSize::Zero(); |
| |
| auto inbound_stats = report->GetStatsOfType<RTCInboundRtpStreamStats>(); |
| for (const auto& stat : inbound_stats) { |
| payload_received += |
| DataSize::Bytes(stat->bytes_received.ValueOrDefault(0ul) + |
| stat->header_bytes_received.ValueOrDefault(0ul)); |
| } |
| |
| auto outbound_stats = report->GetStatsOfType<RTCOutboundRtpStreamStats>(); |
| for (const auto& stat : outbound_stats) { |
| payload_sent += |
| DataSize::Bytes(stat->bytes_sent.ValueOrDefault(0ul) + |
| stat->header_bytes_sent.ValueOrDefault(0ul)); |
| } |
| |
| MutexLock lock(&lock_); |
| PCStats& stats = pc_stats_[std::string(pc_label)]; |
| stats.payload_received = payload_received; |
| stats.payload_sent = payload_sent; |
| } |
| |
| void NetworkQualityMetricsReporter::StopAndReportResults() { |
| EmulatedNetworkStats alice_stats = PopulateStats(alice_network_); |
| EmulatedNetworkStats bob_stats = PopulateStats(bob_network_); |
| int64_t alice_packets_loss = |
| alice_stats.overall_outgoing_stats.packets_sent - |
| bob_stats.overall_incoming_stats.packets_received; |
| int64_t bob_packets_loss = |
| bob_stats.overall_outgoing_stats.packets_sent - |
| alice_stats.overall_incoming_stats.packets_received; |
| ReportStats(alice_network_label_, alice_stats, alice_packets_loss); |
| ReportStats(bob_network_label_, bob_stats, bob_packets_loss); |
| |
| if (!webrtc::field_trial::IsEnabled(kUseStandardBytesStats)) { |
| RTC_LOG(LS_ERROR) |
| << "Non-standard GetStats; \"payload\" counts include RTP headers"; |
| } |
| |
| MutexLock lock(&lock_); |
| for (const auto& pair : pc_stats_) { |
| ReportPCStats(pair.first, pair.second); |
| } |
| } |
| |
| EmulatedNetworkStats NetworkQualityMetricsReporter::PopulateStats( |
| EmulatedNetworkManagerInterface* network) { |
| rtc::Event wait; |
| EmulatedNetworkStats stats; |
| network->GetStats([&](EmulatedNetworkStats s) { |
| stats = std::move(s); |
| wait.Set(); |
| }); |
| bool stats_received = wait.Wait(kStatsWaitTimeout); |
| RTC_CHECK(stats_received); |
| return stats; |
| } |
| |
| void NetworkQualityMetricsReporter::ReportStats( |
| const std::string& network_label, |
| const EmulatedNetworkStats& stats, |
| int64_t packet_loss) { |
| metrics_logger_->LogSingleValueMetric( |
| "bytes_sent", GetTestCaseName(network_label), |
| stats.overall_outgoing_stats.bytes_sent.bytes(), Unit::kBytes, |
| ImprovementDirection::kNeitherIsBetter); |
| metrics_logger_->LogSingleValueMetric( |
| "packets_sent", GetTestCaseName(network_label), |
| stats.overall_outgoing_stats.packets_sent, Unit::kUnitless, |
| ImprovementDirection::kNeitherIsBetter); |
| metrics_logger_->LogSingleValueMetric( |
| "average_send_rate", GetTestCaseName(network_label), |
| stats.overall_outgoing_stats.packets_sent >= 2 |
| ? stats.overall_outgoing_stats.AverageSendRate().kbps<double>() |
| : 0, |
| Unit::kKilobitsPerSecond, ImprovementDirection::kNeitherIsBetter); |
| metrics_logger_->LogSingleValueMetric( |
| "bytes_discarded_no_receiver", GetTestCaseName(network_label), |
| stats.overall_incoming_stats.bytes_discarded_no_receiver.bytes(), |
| Unit::kBytes, ImprovementDirection::kNeitherIsBetter); |
| metrics_logger_->LogSingleValueMetric( |
| "packets_discarded_no_receiver", GetTestCaseName(network_label), |
| stats.overall_incoming_stats.packets_discarded_no_receiver, |
| Unit::kUnitless, ImprovementDirection::kNeitherIsBetter); |
| metrics_logger_->LogSingleValueMetric( |
| "bytes_received", GetTestCaseName(network_label), |
| stats.overall_incoming_stats.bytes_received.bytes(), Unit::kBytes, |
| ImprovementDirection::kNeitherIsBetter); |
| metrics_logger_->LogSingleValueMetric( |
| "packets_received", GetTestCaseName(network_label), |
| stats.overall_incoming_stats.packets_received, Unit::kUnitless, |
| ImprovementDirection::kNeitherIsBetter); |
| metrics_logger_->LogSingleValueMetric( |
| "average_receive_rate", GetTestCaseName(network_label), |
| stats.overall_incoming_stats.packets_received >= 2 |
| ? stats.overall_incoming_stats.AverageReceiveRate().kbps<double>() |
| : 0, |
| Unit::kKilobitsPerSecond, ImprovementDirection::kNeitherIsBetter); |
| metrics_logger_->LogSingleValueMetric( |
| "sent_packets_loss", GetTestCaseName(network_label), packet_loss, |
| Unit::kUnitless, ImprovementDirection::kNeitherIsBetter); |
| } |
| |
| void NetworkQualityMetricsReporter::ReportPCStats(const std::string& pc_label, |
| const PCStats& stats) { |
| metrics_logger_->LogSingleValueMetric( |
| "payload_bytes_received", pc_label, stats.payload_received.bytes(), |
| Unit::kBytes, ImprovementDirection::kNeitherIsBetter); |
| metrics_logger_->LogSingleValueMetric( |
| "payload_bytes_sent", pc_label, stats.payload_sent.bytes(), Unit::kBytes, |
| ImprovementDirection::kNeitherIsBetter); |
| } |
| |
| std::string NetworkQualityMetricsReporter::GetTestCaseName( |
| const std::string& network_label) const { |
| return test_case_name_ + "/" + network_label; |
| } |
| |
| } // namespace webrtc_pc_e2e |
| } // namespace webrtc |