|  | /* | 
|  | *  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/rtc_stats_traversal.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) { | 
|  | const auto& track = static_cast<const RTCMediaStreamTrackStats&>(stats); | 
|  | AddIdIfDefined(track.media_source_id, &neighbor_ids); | 
|  | } 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); | 
|  | if (type == RTCOutboundRTPStreamStats::kType) { | 
|  | const auto& outbound_rtp = | 
|  | static_cast<const RTCOutboundRTPStreamStats&>(stats); | 
|  | AddIdIfDefined(outbound_rtp.media_source_id, &neighbor_ids); | 
|  | } | 
|  | } else if (type == RTCRemoteInboundRtpStreamStats::kType) { | 
|  | const auto& remote_inbound_rtp = | 
|  | static_cast<const RTCRemoteInboundRtpStreamStats&>(stats); | 
|  | AddIdIfDefined(remote_inbound_rtp.transport_id, &neighbor_ids); | 
|  | AddIdIfDefined(remote_inbound_rtp.codec_id, &neighbor_ids); | 
|  | AddIdIfDefined(remote_inbound_rtp.local_id, &neighbor_ids); | 
|  | } else if (type == RTCAudioSourceStats::kType || | 
|  | type == RTCVideoSourceStats::kType) { | 
|  | // RTC[Audio/Video]SourceStats does not have any neighbor references. | 
|  | } 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 |