| /* |
| * Copyright 2016 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. |
| */ |
| |
| #ifndef PC_RTC_STATS_COLLECTOR_H_ |
| #define PC_RTC_STATS_COLLECTOR_H_ |
| |
| #include <stdint.h> |
| |
| #include <cstdint> |
| #include <map> |
| #include <memory> |
| #include <optional> |
| #include <set> |
| #include <string> |
| #include <vector> |
| |
| #include "absl/functional/any_invocable.h" |
| #include "api/audio/audio_device.h" |
| #include "api/data_channel_interface.h" |
| #include "api/environment/environment.h" |
| #include "api/media_types.h" |
| #include "api/rtp_transceiver_direction.h" |
| #include "api/scoped_refptr.h" |
| #include "api/stats/rtc_stats_collector_callback.h" |
| #include "api/stats/rtc_stats_report.h" |
| #include "api/task_queue/pending_task_safety_flag.h" |
| #include "api/task_queue/task_queue_base.h" |
| #include "api/units/timestamp.h" |
| #include "call/call.h" |
| #include "pc/data_channel_utils.h" |
| #include "pc/peer_connection_internal.h" |
| #include "pc/rtp_receiver.h" |
| #include "pc/rtp_sender.h" |
| #include "pc/rtp_transceiver.h" |
| #include "pc/track_media_info_map.h" |
| #include "pc/transport_stats.h" |
| #include "rtc_base/checks.h" |
| #include "rtc_base/containers/flat_set.h" |
| #include "rtc_base/ssl_certificate.h" |
| #include "rtc_base/thread.h" |
| #include "rtc_base/thread_annotations.h" |
| #include "rtc_base/time_utils.h" |
| |
| namespace webrtc { |
| |
| class RtpSenderInternal; |
| class RtpReceiverInternal; |
| |
| // Structure for tracking stats about each RtpTransceiver managed by the |
| // PeerConnection. This can either by a Plan B style or Unified Plan style |
| // transceiver (i.e., can have 0 or many senders and receivers). |
| // Some fields are copied from the RtpTransceiver/BaseChannel object so that |
| // they can be accessed safely on threads other than the signaling thread. |
| // If a BaseChannel is not available (e.g., if signaling has not started), |
| // then `mid` and `transport_name` will be null. |
| struct RtpTransceiverStatsInfo { |
| const MediaType media_type; |
| const std::optional<std::string> mid; |
| std::optional<std::string> transport_name; |
| std::vector<TrackMediaInfoMap::RtpSenderSignalInfo> sender_infos; |
| std::vector<TrackMediaInfoMap::RtpReceiverSignalInfo> receiver_infos; |
| std::unique_ptr<TrackMediaInfoMap> track_media_info_map; |
| const std::optional<RtpTransceiverDirection> current_direction; |
| bool has_receivers = false; |
| const bool has_channel; |
| }; |
| |
| // References to objects used on the signaling and worker threads for populating |
| // RtpTransceiverStatsInfo but must always be released on the signaling thread |
| struct TransceiverReferences { |
| scoped_refptr<RtpTransceiver> transceiver; |
| std::vector<scoped_refptr<RtpReceiverInternal>> receivers; |
| }; |
| |
| // All public methods of the collector are to be called on the signaling thread. |
| // Stats are gathered on the signaling, worker and network threads |
| // asynchronously. The callback is invoked on the signaling thread. Resulting |
| // reports are cached for `cache_lifetime_` ms. |
| class RTCStatsCollector { |
| public: |
| // Gets a recent stats report. If there is a report cached that is still fresh |
| // it is returned, otherwise new stats are gathered and returned. A report is |
| // considered fresh for `cache_lifetime_` ms. const RTCStatsReports are safe |
| // to use across multiple threads and may be destructed on any thread. |
| // If the optional selector argument is used, stats are filtered according to |
| // stats selection algorithm before delivery. |
| // https://w3c.github.io/webrtc-pc/#dfn-stats-selection-algorithm |
| void GetStatsReport(scoped_refptr<RTCStatsCollectorCallback> callback); |
| // If `selector` is null the selection algorithm is still applied (interpreted |
| // as: no RTP streams are sent by selector). The result is empty. |
| void GetStatsReport(scoped_refptr<RtpSenderInternal> selector, |
| scoped_refptr<RTCStatsCollectorCallback> callback); |
| // If `selector` is null the selection algorithm is still applied (interpreted |
| // as: no RTP streams are received by selector). The result is empty. |
| void GetStatsReport(scoped_refptr<RtpReceiverInternal> selector, |
| scoped_refptr<RTCStatsCollectorCallback> callback); |
| // Clears the cache's reference to the most recent stats report. Subsequently |
| // calling `GetStatsReport` guarantees fresh stats. This method must be called |
| // any time the PeerConnection visibly changes as a result of an API call as |
| // per |
| // https://w3c.github.io/webrtc-stats/#guidelines-for-getstats-results-caching-throttling |
| // and it must be called any time negotiation happens. |
| void ClearCachedStatsReport(); |
| |
| // Cancels pending stats gathering operations and prepares for shutdown. |
| // This method adds tasks that the caller needs to make sure is executed |
| // on the worker and network threads before the RTCStatsCollector instance is |
| // deleted. |
| void CancelPendingRequestAndGetShutdownTasks( |
| std::vector<absl::AnyInvocable<void() &&>>& network_tasks, |
| std::vector<absl::AnyInvocable<void() &&>>& worker_tasks); |
| |
| // Called by the PeerConnection instance when data channel states change. |
| void OnSctpDataChannelStateChanged(int channel_id, |
| DataChannelInterface::DataState state); |
| |
| virtual ~RTCStatsCollector(); |
| |
| RTCStatsCollector(PeerConnectionInternal* pc, |
| const Environment& env, |
| int64_t cache_lifetime_us = 50 * kNumMicrosecsPerMillisec); |
| |
| protected: |
| struct CertificateStatsPair { |
| std::unique_ptr<SSLCertificateStats> local; |
| std::unique_ptr<SSLCertificateStats> remote; |
| |
| CertificateStatsPair Copy() const; |
| }; |
| |
| // Stats gathering on a particular thread. Virtual for the sake of testing. |
| virtual void ProducePartialResultsOnSignalingThreadImpl( |
| Timestamp timestamp, |
| const std::vector<RtpTransceiverStatsInfo>& transceiver_stats_infos, |
| const std::vector<TransceiverReferences>& transceiver_references, |
| const std::optional<AudioDeviceModule::Stats>& audio_device_stats, |
| RTCStatsReport* partial_report); |
| |
| void ProcessResultsFromNetworkThread( |
| Timestamp timestamp, |
| std::map<std::string, TransportStats> transport_stats_by_name, |
| std::map<std::string, CertificateStatsPair> transport_cert_stats, |
| std::vector<RtpTransceiverStatsInfo> transceiver_stats_infos, |
| Call::Stats call_stats, |
| std::optional<AudioDeviceModule::Stats> audio_device_stats, |
| RTCStatsReport* partial_report); |
| |
| private: |
| struct StatsGatheringResults { |
| std::vector<RtpTransceiverStatsInfo> transceiver_stats_infos; |
| Call::Stats call_stats; |
| std::optional<AudioDeviceModule::Stats> audio_device_stats; |
| }; |
| |
| struct WorkerThreadResult { |
| StatsGatheringResults results; |
| std::vector<TransceiverReferences> transceiver_references; |
| }; |
| struct CollectionContext; |
| class RequestInfo { |
| public: |
| enum class FilterMode { kAll, kSenderSelector, kReceiverSelector }; |
| |
| // Constructs with FilterMode::kAll. |
| explicit RequestInfo(scoped_refptr<RTCStatsCollectorCallback> callback); |
| // Constructs with FilterMode::kSenderSelector. The selection algorithm is |
| // applied even if `selector` is null, resulting in an empty report. |
| RequestInfo(scoped_refptr<RtpSenderInternal> selector, |
| scoped_refptr<RTCStatsCollectorCallback> callback); |
| // Constructs with FilterMode::kReceiverSelector. The selection algorithm is |
| // applied even if `selector` is null, resulting in an empty report. |
| RequestInfo(scoped_refptr<RtpReceiverInternal> selector, |
| scoped_refptr<RTCStatsCollectorCallback> callback); |
| |
| FilterMode filter_mode() const { return filter_mode_; } |
| scoped_refptr<RTCStatsCollectorCallback> callback() const { |
| return callback_; |
| } |
| scoped_refptr<RtpSenderInternal> sender_selector() const { |
| RTC_DCHECK(filter_mode_ == FilterMode::kSenderSelector); |
| return sender_selector_; |
| } |
| scoped_refptr<RtpReceiverInternal> receiver_selector() const { |
| RTC_DCHECK(filter_mode_ == FilterMode::kReceiverSelector); |
| return receiver_selector_; |
| } |
| |
| private: |
| RequestInfo(FilterMode filter_mode, |
| scoped_refptr<RTCStatsCollectorCallback> callback, |
| scoped_refptr<RtpSenderInternal> sender_selector, |
| scoped_refptr<RtpReceiverInternal> receiver_selector); |
| |
| FilterMode filter_mode_; |
| scoped_refptr<RTCStatsCollectorCallback> callback_; |
| scoped_refptr<RtpSenderInternal> sender_selector_; |
| scoped_refptr<RtpReceiverInternal> receiver_selector_; |
| }; |
| |
| void GetStatsReportInternal(RequestInfo request); |
| |
| // Invokes the completion callback for a pending request. |
| void DeliverReport(const RequestInfo& request, |
| const scoped_refptr<const RTCStatsReport>& report); |
| |
| // Produces `RTCCertificateStats`. |
| void ProduceCertificateStats_s( |
| Timestamp timestamp, |
| const std::map<std::string, CertificateStatsPair>& transport_cert_stats, |
| RTCStatsReport* report) const; |
| // Produces `RTCDataChannelStats`. |
| void ProduceDataChannelStats_s( |
| Timestamp timestamp, |
| const std::vector<DataChannelStats>& data_channel_stats, |
| RTCStatsReport* report) const; |
| // Produces `RTCIceCandidatePairStats` and `RTCIceCandidateStats`. |
| void ProduceIceCandidateAndPairStats_s( |
| Timestamp timestamp, |
| const std::map<std::string, TransportStats>& transport_stats_by_name, |
| const Call::Stats& call_stats, |
| RTCStatsReport* report) const; |
| // Produces RTCMediaSourceStats, including RTCAudioSourceStats and |
| // RTCVideoSourceStats. |
| void ProduceMediaSourceStats_s( |
| Timestamp timestamp, |
| const std::vector<RtpTransceiverStatsInfo>& transceiver_stats_infos, |
| const std::vector<TransceiverReferences>& transceiver_references, |
| RTCStatsReport* report) const; |
| // Produces `RTCPeerConnectionStats`. |
| void ProducePeerConnectionStats_s(Timestamp timestamp, |
| RTCStatsReport* report) const; |
| // Produces `RTCAudioPlayoutStats`. |
| void ProduceAudioPlayoutStats_s( |
| Timestamp timestamp, |
| const std::optional<AudioDeviceModule::Stats>& audio_device_stats, |
| RTCStatsReport* report) const; |
| // Produces `RTCInboundRtpStreamStats`, `RTCOutboundRtpStreamStats`, |
| // `RTCRemoteInboundRtpStreamStats`, `RTCRemoteOutboundRtpStreamStats` and any |
| // referenced `RTCCodecStats`. This has to be invoked after transport stats |
| // have been created because some metrics are calculated through lookup of |
| // other metrics. |
| void ProduceRTPStreamStats_s( |
| Timestamp timestamp, |
| const std::vector<RtpTransceiverStatsInfo>& transceiver_stats_infos, |
| const Call::Stats& call_stats, |
| const std::optional<AudioDeviceModule::Stats>& audio_device_stats, |
| RTCStatsReport* report) const; |
| void ProduceAudioRTPStreamStats_s( |
| Timestamp timestamp, |
| const RtpTransceiverStatsInfo& stats, |
| const Call::Stats& call_stats, |
| const std::optional<AudioDeviceModule::Stats>& audio_device_stats, |
| RTCStatsReport* report) const; |
| void ProduceVideoRTPStreamStats_s(Timestamp timestamp, |
| const RtpTransceiverStatsInfo& stats, |
| const Call::Stats& call_stats, |
| RTCStatsReport* report) const; |
| // Produces `RTCTransportStats`. |
| void ProduceTransportStats_s( |
| Timestamp timestamp, |
| const std::map<std::string, TransportStats>& transport_stats_by_name, |
| const std::map<std::string, CertificateStatsPair>& transport_cert_stats, |
| const Call::Stats& call_stats, |
| RTCStatsReport* report) const; |
| |
| // Helper function to stats-producing functions. |
| std::map<std::string, CertificateStatsPair> |
| PrepareTransportCertificateStats_n( |
| const std::map<std::string, TransportStats>& transport_stats_by_name); |
| // The results are stored in `transceiver_stats_infos_` and `call_stats_`. |
| // Prepares the transceiver stats infos and call stats. |
| // Returns a callback that should be executed on the worker thread to populate |
| // the stats. |
| absl::AnyInvocable<WorkerThreadResult()> |
| PrepareTransceiverStatsInfosAndCallStats_s_w(); |
| |
| // Stats gathering on a particular thread. |
| void ProducePartialResultsOnSignalingThread( |
| const std::vector<RtpTransceiverStatsInfo>& transceiver_stats_infos, |
| const std::vector<TransceiverReferences>& transceiver_references, |
| const std::optional<AudioDeviceModule::Stats>& audio_device_stats); |
| void ProducePartialResultsOnNetworkThread( |
| scoped_refptr<PendingTaskSafetyFlag> signaling_safety, |
| Timestamp timestamp, |
| std::set<std::string> transport_names, |
| StatsGatheringResults results); |
| // Merges `network_report` into `partial_report_` and completes the request. |
| void OnNetworkReportReady(scoped_refptr<RTCStatsReport> network_report, |
| std::vector<DataChannelStats> data_channel_stats); |
| |
| scoped_refptr<RTCStatsReport> CreateReportFilteredBySelector( |
| bool filter_by_sender_selector, |
| scoped_refptr<const RTCStatsReport> report, |
| scoped_refptr<RtpSenderInternal> sender_selector, |
| scoped_refptr<RtpReceiverInternal> receiver_selector); |
| |
| PeerConnectionInternal* const pc_; |
| const bool is_unified_plan_; |
| const Environment env_; |
| const bool stats_timestamp_with_environment_clock_; |
| TaskQueueBase* const signaling_thread_; |
| Thread* const worker_thread_; |
| Thread* const network_thread_; |
| |
| std::vector<RequestInfo> requests_ RTC_GUARDED_BY(signaling_thread_); |
| |
| // This cache avoids having to call webrtc::SSLCertChain::GetStats(), which |
| // can relatively expensive. ClearCachedStatsReport() needs to be called on |
| // negotiation to ensure the cache is not obsolete. |
| std::map<std::string, CertificateStatsPair> cached_certificates_by_transport_ |
| RTC_GUARDED_BY(network_thread_); |
| |
| // A timestamp, in microseconds, that is based on a timer that is |
| // monotonically increasing. That is, even if the system clock is modified the |
| // difference between the timer and this timestamp is how fresh the cached |
| // report is. |
| int64_t cache_timestamp_us_; |
| int64_t cache_lifetime_us_; |
| scoped_refptr<const RTCStatsReport> cached_report_ |
| RTC_GUARDED_BY(signaling_thread_); |
| |
| // Data recorded and maintained by the stats collector during its lifetime. |
| // Some stats are produced from this record instead of other components. |
| struct InternalRecord { |
| InternalRecord() : data_channels_opened(0), data_channels_closed(0) {} |
| |
| // The opened count goes up when a channel is fully opened and the closed |
| // count goes up if a previously opened channel has fully closed. The opened |
| // count does not go down when a channel closes, meaning (opened - closed) |
| // is the number of channels currently opened. A channel that is closed |
| // before reaching the open state does not affect these counters. |
| uint32_t data_channels_opened; |
| uint32_t data_channels_closed; |
| // Identifies channels that have been opened, whose internal id is stored in |
| // the set until they have been fully closed. |
| flat_set<int> opened_data_channels; |
| }; |
| InternalRecord internal_record_; |
| const scoped_refptr<PendingTaskSafetyFlag> signaling_safety_; |
| const scoped_refptr<PendingTaskSafetyFlag> worker_safety_; |
| const scoped_refptr<PendingTaskSafetyFlag> network_safety_; |
| |
| std::unique_ptr<CollectionContext> collection_context_ |
| RTC_GUARDED_BY(signaling_thread_); |
| }; |
| |
| } // namespace webrtc |
| |
| #endif // PC_RTC_STATS_COLLECTOR_H_ |