| /* | |
| * 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 <optional> | |
| #include <string> | |
| #include <utility> | |
| #include <vector> | |
| #include "api/scoped_refptr.h" | |
| #include "api/stats/rtc_stats.h" | |
| #include "api/stats/rtc_stats_report.h" | |
| #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 std::optional<std::string>& id, | |
| std::vector<const std::string*>* neighbor_ids) { | |
| if (id.has_value()) | |
| neighbor_ids->push_back(&(*id)); | |
| } | |
| } // namespace | |
| scoped_refptr<RTCStatsReport> TakeReferencedStats( | |
| scoped_refptr<RTCStatsReport> report, | |
| const std::vector<std::string>& ids) { | |
| scoped_refptr<RTCStatsReport> result = | |
| RTCStatsReport::Create(report->timestamp()); | |
| 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) { | |
| const auto& codec = static_cast<const RTCCodecStats&>(stats); | |
| AddIdIfDefined(codec.transport_id, &neighbor_ids); | |
| } 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 == RTCPeerConnectionStats::kType) { | |
| // RTCPeerConnectionStats does not have any neighbor references. | |
| } else if (type == RTCInboundRtpStreamStats::kType) { | |
| const auto& inbound_rtp = | |
| static_cast<const RTCInboundRtpStreamStats&>(stats); | |
| AddIdIfDefined(inbound_rtp.remote_id, &neighbor_ids); | |
| AddIdIfDefined(inbound_rtp.transport_id, &neighbor_ids); | |
| AddIdIfDefined(inbound_rtp.codec_id, &neighbor_ids); | |
| AddIdIfDefined(inbound_rtp.playout_id, &neighbor_ids); | |
| } else if (type == RTCOutboundRtpStreamStats::kType) { | |
| const auto& outbound_rtp = | |
| static_cast<const RTCOutboundRtpStreamStats&>(stats); | |
| AddIdIfDefined(outbound_rtp.remote_id, &neighbor_ids); | |
| AddIdIfDefined(outbound_rtp.transport_id, &neighbor_ids); | |
| AddIdIfDefined(outbound_rtp.codec_id, &neighbor_ids); | |
| 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 == RTCRemoteOutboundRtpStreamStats::kType) { | |
| const auto& remote_outbound_rtp = | |
| static_cast<const RTCRemoteOutboundRtpStreamStats&>(stats); | |
| // Inherited from `RTCRTPStreamStats`. | |
| AddIdIfDefined(remote_outbound_rtp.transport_id, &neighbor_ids); | |
| AddIdIfDefined(remote_outbound_rtp.codec_id, &neighbor_ids); | |
| // Direct members of `RTCRemoteOutboundRtpStreamStats`. | |
| AddIdIfDefined(remote_outbound_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) { | |
| 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 if (type == RTCAudioPlayoutStats::kType) { | |
| // RTCAudioPlayoutStats does not have any neighbor references. | |
| } else { | |
| RTC_DCHECK_NOTREACHED() << "Unrecognized type: " << type; | |
| } | |
| return neighbor_ids; | |
| } | |
| } // namespace webrtc |