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