| /* | 
 |  *  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 <memory> | 
 | #include <string> | 
 | #include <utility> | 
 | #include <vector> | 
 |  | 
 | #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<const RTCStats> current = report->Take(current_id); | 
 |   if (!current) { | 
 |     // This node has already been visited (or it is an invalid id). | 
 |     return; | 
 |   } | 
 |   std::vector<const std::string*> 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<std::string>& id, | 
 |                     std::vector<const std::string*>* neighbor_ids) { | 
 |   if (id.is_defined()) | 
 |     neighbor_ids->push_back(&(*id)); | 
 | } | 
 |  | 
 | void AddIdsIfDefined(const RTCStatsMember<std::vector<std::string>>& ids, | 
 |                      std::vector<const std::string*>* neighbor_ids) { | 
 |   if (ids.is_defined()) { | 
 |     for (const std::string& id : *ids) | 
 |       neighbor_ids->push_back(&id); | 
 |   } | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | rtc::scoped_refptr<RTCStatsReport> TakeReferencedStats( | 
 |     rtc::scoped_refptr<RTCStatsReport> report, | 
 |     const std::vector<std::string>& ids) { | 
 |   rtc::scoped_refptr<RTCStatsReport> result = | 
 |       RTCStatsReport::Create(report->timestamp_us()); | 
 |   for (const auto& id : ids) { | 
 |     TraverseAndTakeVisitedStats(report.get(), result.get(), id); | 
 |   } | 
 |   return result; | 
 | } | 
 |  | 
 | std::vector<const std::string*> GetStatsReferencedIds(const RTCStats& stats) { | 
 |   std::vector<const std::string*> neighbor_ids; | 
 |   const char* type = stats.type(); | 
 |   if (type == RTCCertificateStats::kType) { | 
 |     const auto& certificate = static_cast<const RTCCertificateStats&>(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<const RTCIceCandidatePairStats&>(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<const RTCIceCandidateStats&>(stats); | 
 |     AddIdIfDefined(local_or_remote_candidate.transport_id, &neighbor_ids); | 
 |   } else if (type == RTCMediaStreamStats::kType) { | 
 |     const auto& stream = static_cast<const RTCMediaStreamStats&>(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<const RTCRTPStreamStats&>(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<const RTCTransportStats&>(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 |