/* * 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 #include #include #include #include #include #include "absl/types/optional.h" #include "api/data_channel_interface.h" #include "api/media_types.h" #include "api/scoped_refptr.h" #include "api/stats/rtc_stats_collector_callback.h" #include "api/stats/rtc_stats_report.h" #include "api/stats/rtcstats_objects.h" #include "call/call.h" #include "media/base/media_channel.h" #include "modules/audio_device/include/audio_device.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/sctp_data_channel.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/event.h" #include "rtc_base/ref_count.h" #include "rtc_base/ssl_certificate.h" #include "rtc_base/ssl_identity.h" #include "rtc_base/synchronization/mutex.h" #include "rtc_base/thread.h" #include "rtc_base/time_utils.h" namespace webrtc { class RtpSenderInternal; class RtpReceiverInternal; // 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 rtc::RefCountInterface { public: static rtc::scoped_refptr Create( PeerConnectionInternal* pc, int64_t cache_lifetime_us = 50 * rtc::kNumMicrosecsPerMillisec); // 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(rtc::scoped_refptr 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(rtc::scoped_refptr selector, rtc::scoped_refptr 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(rtc::scoped_refptr selector, rtc::scoped_refptr 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(); // If there is a `GetStatsReport` requests in-flight, waits until it has been // completed. Must be called on the signaling thread. void WaitForPendingRequest(); // Called by the PeerConnection instance when data channel states change. void OnSctpDataChannelStateChanged(int channel_id, DataChannelInterface::DataState state); protected: RTCStatsCollector(PeerConnectionInternal* pc, int64_t cache_lifetime_us); ~RTCStatsCollector(); struct CertificateStatsPair { std::unique_ptr local; std::unique_ptr remote; CertificateStatsPair Copy() const; }; // Stats gathering on a particular thread. Virtual for the sake of testing. virtual void ProducePartialResultsOnSignalingThreadImpl( Timestamp timestamp, RTCStatsReport* partial_report); virtual void ProducePartialResultsOnNetworkThreadImpl( Timestamp timestamp, const std::map& transport_stats_by_name, const std::map& transport_cert_stats, RTCStatsReport* partial_report); private: class RequestInfo { public: enum class FilterMode { kAll, kSenderSelector, kReceiverSelector }; // Constructs with FilterMode::kAll. explicit RequestInfo( rtc::scoped_refptr callback); // Constructs with FilterMode::kSenderSelector. The selection algorithm is // applied even if `selector` is null, resulting in an empty report. RequestInfo(rtc::scoped_refptr selector, rtc::scoped_refptr callback); // Constructs with FilterMode::kReceiverSelector. The selection algorithm is // applied even if `selector` is null, resulting in an empty report. RequestInfo(rtc::scoped_refptr selector, rtc::scoped_refptr callback); FilterMode filter_mode() const { return filter_mode_; } rtc::scoped_refptr callback() const { return callback_; } rtc::scoped_refptr sender_selector() const { RTC_DCHECK(filter_mode_ == FilterMode::kSenderSelector); return sender_selector_; } rtc::scoped_refptr receiver_selector() const { RTC_DCHECK(filter_mode_ == FilterMode::kReceiverSelector); return receiver_selector_; } private: RequestInfo(FilterMode filter_mode, rtc::scoped_refptr callback, rtc::scoped_refptr sender_selector, rtc::scoped_refptr receiver_selector); FilterMode filter_mode_; rtc::scoped_refptr callback_; rtc::scoped_refptr sender_selector_; rtc::scoped_refptr receiver_selector_; }; void GetStatsReportInternal(RequestInfo request); // 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 { rtc::scoped_refptr transceiver; cricket::MediaType media_type; absl::optional mid; absl::optional transport_name; TrackMediaInfoMap track_media_info_map; absl::optional current_direction; }; void DeliverCachedReport( rtc::scoped_refptr cached_report, std::vector requests); // Produces `RTCCertificateStats`. void ProduceCertificateStats_n( Timestamp timestamp, const std::map& transport_cert_stats, RTCStatsReport* report) const; // Produces `RTCDataChannelStats`. void ProduceDataChannelStats_n(Timestamp timestamp, RTCStatsReport* report) const; // Produces `RTCIceCandidatePairStats` and `RTCIceCandidateStats`. void ProduceIceCandidateAndPairStats_n( Timestamp timestamp, const std::map& transport_stats_by_name, const Call::Stats& call_stats, RTCStatsReport* report) const; // Produces RTCMediaSourceStats, including RTCAudioSourceStats and // RTCVideoSourceStats. void ProduceMediaSourceStats_s(Timestamp timestamp, RTCStatsReport* report) const; // Produces `RTCPeerConnectionStats`. void ProducePeerConnectionStats_s(Timestamp timestamp, RTCStatsReport* report) const; // Produces `RTCAudioPlayoutStats`. void ProduceAudioPlayoutStats_s(Timestamp timestamp, 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_n( Timestamp timestamp, const std::vector& transceiver_stats_infos, RTCStatsReport* report) const; void ProduceAudioRTPStreamStats_n(Timestamp timestamp, const RtpTransceiverStatsInfo& stats, RTCStatsReport* report) const; void ProduceVideoRTPStreamStats_n(Timestamp timestamp, const RtpTransceiverStatsInfo& stats, RTCStatsReport* report) const; // Produces `RTCTransportStats`. void ProduceTransportStats_n( Timestamp timestamp, const std::map& transport_stats_by_name, const std::map& transport_cert_stats, RTCStatsReport* report) const; // Helper function to stats-producing functions. std::map PrepareTransportCertificateStats_n( const std::map& transport_stats_by_name); // The results are stored in `transceiver_stats_infos_` and `call_stats_`. void PrepareTransceiverStatsInfosAndCallStats_s_w_n(); // Stats gathering on a particular thread. void ProducePartialResultsOnSignalingThread(Timestamp timestamp); void ProducePartialResultsOnNetworkThread( Timestamp timestamp, absl::optional sctp_transport_name); // Merges `network_report_` into `partial_report_` and completes the request. // This is a NO-OP if `network_report_` is null. void MergeNetworkReport_s(); rtc::scoped_refptr CreateReportFilteredBySelector( bool filter_by_sender_selector, rtc::scoped_refptr report, rtc::scoped_refptr sender_selector, rtc::scoped_refptr receiver_selector); PeerConnectionInternal* const pc_; rtc::Thread* const signaling_thread_; rtc::Thread* const worker_thread_; rtc::Thread* const network_thread_; int num_pending_partial_reports_; int64_t partial_report_timestamp_us_; // Reports that are produced on the signaling thread or the network thread are // merged into this report. It is only touched on the signaling thread. Once // all partial reports are merged this is the result of a request. rtc::scoped_refptr partial_report_; std::vector requests_; // Holds the result of ProducePartialResultsOnNetworkThread(). It is merged // into `partial_report_` on the signaling thread and then nulled by // MergeNetworkReport_s(). Thread-safety is ensured by using // `network_report_event_`. rtc::scoped_refptr network_report_; // If set, it is safe to touch the `network_report_` on the signaling thread. // This is reset before async-invoking ProducePartialResultsOnNetworkThread() // and set when ProducePartialResultsOnNetworkThread() is complete, after it // has updated the value of `network_report_`. rtc::Event network_report_event_; // Cleared and set in `PrepareTransceiverStatsInfosAndCallStats_s_w_n`, // starting out on the signaling thread, then network. Later read on the // network and signaling threads as part of collecting stats and finally // reset when the work is done. Initially this variable was added and not // passed around as an arguments to avoid copies. This is thread safe due to // how operations are sequenced and we don't start the stats collection // sequence if one is in progress. As a future improvement though, we could // now get rid of the variable and keep the data scoped within a stats // collection sequence. std::vector transceiver_stats_infos_; // This cache avoids having to call rtc::SSLCertChain::GetStats(), which can // relatively expensive. ClearCachedStatsReport() needs to be called on // negotiation to ensure the cache is not obsolete. Mutex cached_certificates_mutex_; std::map cached_certificates_by_transport_ RTC_GUARDED_BY(cached_certificates_mutex_); Call::Stats call_stats_; absl::optional audio_device_stats_; // 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_; rtc::scoped_refptr cached_report_; // 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 opened_data_channels; }; InternalRecord internal_record_; }; } // namespace webrtc #endif // PC_RTC_STATS_COLLECTOR_H_