1 /*
2  *  Copyright 2018 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 "pc/rtc_stats_traversal.h"
12 
13 #include <memory>
14 #include <string>
15 #include <utility>
16 #include <vector>
17 
18 #include "api/stats/rtcstats_objects.h"
19 #include "rtc_base/checks.h"
20 
21 namespace webrtc {
22 
23 namespace {
24 
TraverseAndTakeVisitedStats(RTCStatsReport * report,RTCStatsReport * visited_report,const std::string & current_id)25 void TraverseAndTakeVisitedStats(RTCStatsReport* report,
26                                  RTCStatsReport* visited_report,
27                                  const std::string& current_id) {
28   // Mark current stats object as visited by moving it |report| to
29   // |visited_report|.
30   std::unique_ptr<const RTCStats> current = report->Take(current_id);
31   if (!current) {
32     // This node has already been visited (or it is an invalid id).
33     return;
34   }
35   std::vector<const std::string*> neighbor_ids =
36       GetStatsReferencedIds(*current);
37   visited_report->AddStats(std::move(current));
38 
39   // Recursively traverse all neighbors.
40   for (const auto* neighbor_id : neighbor_ids) {
41     TraverseAndTakeVisitedStats(report, visited_report, *neighbor_id);
42   }
43 }
44 
AddIdIfDefined(const RTCStatsMember<std::string> & id,std::vector<const std::string * > * neighbor_ids)45 void AddIdIfDefined(const RTCStatsMember<std::string>& id,
46                     std::vector<const std::string*>* neighbor_ids) {
47   if (id.is_defined())
48     neighbor_ids->push_back(&(*id));
49 }
50 
AddIdsIfDefined(const RTCStatsMember<std::vector<std::string>> & ids,std::vector<const std::string * > * neighbor_ids)51 void AddIdsIfDefined(const RTCStatsMember<std::vector<std::string>>& ids,
52                      std::vector<const std::string*>* neighbor_ids) {
53   if (ids.is_defined()) {
54     for (const std::string& id : *ids)
55       neighbor_ids->push_back(&id);
56   }
57 }
58 
59 }  // namespace
60 
TakeReferencedStats(rtc::scoped_refptr<RTCStatsReport> report,const std::vector<std::string> & ids)61 rtc::scoped_refptr<RTCStatsReport> TakeReferencedStats(
62     rtc::scoped_refptr<RTCStatsReport> report,
63     const std::vector<std::string>& ids) {
64   rtc::scoped_refptr<RTCStatsReport> result =
65       RTCStatsReport::Create(report->timestamp_us());
66   for (const auto& id : ids) {
67     TraverseAndTakeVisitedStats(report.get(), result.get(), id);
68   }
69   return result;
70 }
71 
GetStatsReferencedIds(const RTCStats & stats)72 std::vector<const std::string*> GetStatsReferencedIds(const RTCStats& stats) {
73   std::vector<const std::string*> neighbor_ids;
74   const char* type = stats.type();
75   if (type == RTCCertificateStats::kType) {
76     const auto& certificate = static_cast<const RTCCertificateStats&>(stats);
77     AddIdIfDefined(certificate.issuer_certificate_id, &neighbor_ids);
78   } else if (type == RTCCodecStats::kType) {
79     // RTCCodecStats does not have any neighbor references.
80   } else if (type == RTCDataChannelStats::kType) {
81     // RTCDataChannelStats does not have any neighbor references.
82   } else if (type == RTCIceCandidatePairStats::kType) {
83     const auto& candidate_pair =
84         static_cast<const RTCIceCandidatePairStats&>(stats);
85     AddIdIfDefined(candidate_pair.transport_id, &neighbor_ids);
86     AddIdIfDefined(candidate_pair.local_candidate_id, &neighbor_ids);
87     AddIdIfDefined(candidate_pair.remote_candidate_id, &neighbor_ids);
88   } else if (type == RTCLocalIceCandidateStats::kType ||
89              type == RTCRemoteIceCandidateStats::kType) {
90     const auto& local_or_remote_candidate =
91         static_cast<const RTCIceCandidateStats&>(stats);
92     AddIdIfDefined(local_or_remote_candidate.transport_id, &neighbor_ids);
93   } else if (type == RTCMediaStreamStats::kType) {
94     const auto& stream = static_cast<const RTCMediaStreamStats&>(stats);
95     AddIdsIfDefined(stream.track_ids, &neighbor_ids);
96   } else if (type == RTCMediaStreamTrackStats::kType) {
97     const auto& track = static_cast<const RTCMediaStreamTrackStats&>(stats);
98     AddIdIfDefined(track.media_source_id, &neighbor_ids);
99   } else if (type == RTCPeerConnectionStats::kType) {
100     // RTCPeerConnectionStats does not have any neighbor references.
101   } else if (type == RTCInboundRTPStreamStats::kType ||
102              type == RTCOutboundRTPStreamStats::kType) {
103     const auto& rtp = static_cast<const RTCRTPStreamStats&>(stats);
104     AddIdIfDefined(rtp.track_id, &neighbor_ids);
105     AddIdIfDefined(rtp.transport_id, &neighbor_ids);
106     AddIdIfDefined(rtp.codec_id, &neighbor_ids);
107     if (type == RTCOutboundRTPStreamStats::kType) {
108       const auto& outbound_rtp =
109           static_cast<const RTCOutboundRTPStreamStats&>(stats);
110       AddIdIfDefined(outbound_rtp.media_source_id, &neighbor_ids);
111       AddIdIfDefined(outbound_rtp.remote_id, &neighbor_ids);
112     }
113   } else if (type == RTCRemoteInboundRtpStreamStats::kType) {
114     const auto& remote_inbound_rtp =
115         static_cast<const RTCRemoteInboundRtpStreamStats&>(stats);
116     AddIdIfDefined(remote_inbound_rtp.transport_id, &neighbor_ids);
117     AddIdIfDefined(remote_inbound_rtp.codec_id, &neighbor_ids);
118     AddIdIfDefined(remote_inbound_rtp.local_id, &neighbor_ids);
119   } else if (type == RTCAudioSourceStats::kType ||
120              type == RTCVideoSourceStats::kType) {
121     // RTC[Audio/Video]SourceStats does not have any neighbor references.
122   } else if (type == RTCTransportStats::kType) {
123     // RTCTransportStats does not have any neighbor references.
124     const auto& transport = static_cast<const RTCTransportStats&>(stats);
125     AddIdIfDefined(transport.rtcp_transport_stats_id, &neighbor_ids);
126     AddIdIfDefined(transport.selected_candidate_pair_id, &neighbor_ids);
127     AddIdIfDefined(transport.local_certificate_id, &neighbor_ids);
128     AddIdIfDefined(transport.remote_certificate_id, &neighbor_ids);
129   } else {
130     RTC_NOTREACHED() << "Unrecognized type: " << type;
131   }
132   return neighbor_ids;
133 }
134 
135 }  // namespace webrtc
136