/* * Copyright 2018 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 "pc/rtcstatstraversal.h" #include #include #include #include #include "api/stats/rtcstats_objects.h" #include "rtc_base/checks.h" namespace webrtc { namespace { void TraverseAndTakeVisitedStats(RTCStatsReport* report, RTCStatsReport* visited_report, const std::string& current_id) { // Mark current stats object as visited by moving it |report| to // |visited_report|. std::unique_ptr current = report->Take(current_id); if (!current) { // This node has already been visited (or it is an invalid id). return; } std::vector neighbor_ids = GetStatsReferencedIds(*current); visited_report->AddStats(std::move(current)); // Recursively traverse all neighbors. for (const auto* neighbor_id : neighbor_ids) { TraverseAndTakeVisitedStats(report, visited_report, *neighbor_id); } } void AddIdIfDefined(const RTCStatsMember& id, std::vector* neighbor_ids) { if (id.is_defined()) neighbor_ids->push_back(&(*id)); } void AddIdsIfDefined(const RTCStatsMember>& ids, std::vector* neighbor_ids) { if (ids.is_defined()) { for (const std::string& id : *ids) neighbor_ids->push_back(&id); } } } // namespace rtc::scoped_refptr TakeReferencedStats( rtc::scoped_refptr report, const std::vector& ids) { rtc::scoped_refptr result = RTCStatsReport::Create(report->timestamp_us()); for (const auto& id : ids) { TraverseAndTakeVisitedStats(report.get(), result.get(), id); } return result; } std::vector GetStatsReferencedIds(const RTCStats& stats) { std::vector neighbor_ids; const char* type = stats.type(); if (type == RTCCertificateStats::kType) { const auto& certificate = static_cast(stats); AddIdIfDefined(certificate.issuer_certificate_id, &neighbor_ids); } else if (type == RTCCodecStats::kType) { // RTCCodecStats does not have any neighbor references. } else if (type == RTCDataChannelStats::kType) { // RTCDataChannelStats does not have any neighbor references. } else if (type == RTCIceCandidatePairStats::kType) { const auto& candidate_pair = static_cast(stats); AddIdIfDefined(candidate_pair.transport_id, &neighbor_ids); AddIdIfDefined(candidate_pair.local_candidate_id, &neighbor_ids); AddIdIfDefined(candidate_pair.remote_candidate_id, &neighbor_ids); } else if (type == RTCLocalIceCandidateStats::kType || type == RTCRemoteIceCandidateStats::kType) { const auto& local_or_remote_candidate = static_cast(stats); AddIdIfDefined(local_or_remote_candidate.transport_id, &neighbor_ids); } else if (type == RTCMediaStreamStats::kType) { const auto& stream = static_cast(stats); AddIdsIfDefined(stream.track_ids, &neighbor_ids); } else if (type == RTCMediaStreamTrackStats::kType) { // RTCMediaStreamTrackStats does not have any neighbor references. } else if (type == RTCPeerConnectionStats::kType) { // RTCPeerConnectionStats does not have any neighbor references. } else if (type == RTCInboundRTPStreamStats::kType || type == RTCOutboundRTPStreamStats::kType) { const auto& rtp = static_cast(stats); AddIdIfDefined(rtp.associate_stats_id, &neighbor_ids); AddIdIfDefined(rtp.track_id, &neighbor_ids); AddIdIfDefined(rtp.transport_id, &neighbor_ids); AddIdIfDefined(rtp.codec_id, &neighbor_ids); } else if (type == RTCTransportStats::kType) { // RTCTransportStats does not have any neighbor references. const auto& transport = static_cast(stats); AddIdIfDefined(transport.rtcp_transport_stats_id, &neighbor_ids); AddIdIfDefined(transport.selected_candidate_pair_id, &neighbor_ids); AddIdIfDefined(transport.local_certificate_id, &neighbor_ids); AddIdIfDefined(transport.remote_certificate_id, &neighbor_ids); } else { RTC_NOTREACHED() << "Unrecognized type: " << type; } return neighbor_ids; } } // namespace webrtc