xref: /aosp_15_r20/external/webrtc/pc/rtc_stats_collector.h (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright 2016 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 #ifndef PC_RTC_STATS_COLLECTOR_H_
12 #define PC_RTC_STATS_COLLECTOR_H_
13 
14 #include <stdint.h>
15 
16 #include <cstdint>
17 #include <map>
18 #include <memory>
19 #include <set>
20 #include <string>
21 #include <vector>
22 
23 #include "absl/types/optional.h"
24 #include "api/data_channel_interface.h"
25 #include "api/media_types.h"
26 #include "api/scoped_refptr.h"
27 #include "api/stats/rtc_stats_collector_callback.h"
28 #include "api/stats/rtc_stats_report.h"
29 #include "api/stats/rtcstats_objects.h"
30 #include "call/call.h"
31 #include "media/base/media_channel.h"
32 #include "pc/data_channel_utils.h"
33 #include "pc/peer_connection_internal.h"
34 #include "pc/rtp_receiver.h"
35 #include "pc/rtp_sender.h"
36 #include "pc/rtp_transceiver.h"
37 #include "pc/sctp_data_channel.h"
38 #include "pc/track_media_info_map.h"
39 #include "pc/transport_stats.h"
40 #include "rtc_base/checks.h"
41 #include "rtc_base/event.h"
42 #include "rtc_base/ref_count.h"
43 #include "rtc_base/ssl_certificate.h"
44 #include "rtc_base/ssl_identity.h"
45 #include "rtc_base/synchronization/mutex.h"
46 #include "rtc_base/third_party/sigslot/sigslot.h"
47 #include "rtc_base/thread.h"
48 #include "rtc_base/time_utils.h"
49 
50 namespace webrtc {
51 
52 class RtpSenderInternal;
53 class RtpReceiverInternal;
54 
55 // All public methods of the collector are to be called on the signaling thread.
56 // Stats are gathered on the signaling, worker and network threads
57 // asynchronously. The callback is invoked on the signaling thread. Resulting
58 // reports are cached for `cache_lifetime_` ms.
59 class RTCStatsCollector : public rtc::RefCountInterface,
60                           public sigslot::has_slots<> {
61  public:
62   static rtc::scoped_refptr<RTCStatsCollector> Create(
63       PeerConnectionInternal* pc,
64       int64_t cache_lifetime_us = 50 * rtc::kNumMicrosecsPerMillisec);
65 
66   // Gets a recent stats report. If there is a report cached that is still fresh
67   // it is returned, otherwise new stats are gathered and returned. A report is
68   // considered fresh for `cache_lifetime_` ms. const RTCStatsReports are safe
69   // to use across multiple threads and may be destructed on any thread.
70   // If the optional selector argument is used, stats are filtered according to
71   // stats selection algorithm before delivery.
72   // https://w3c.github.io/webrtc-pc/#dfn-stats-selection-algorithm
73   void GetStatsReport(rtc::scoped_refptr<RTCStatsCollectorCallback> callback);
74   // If `selector` is null the selection algorithm is still applied (interpreted
75   // as: no RTP streams are sent by selector). The result is empty.
76   void GetStatsReport(rtc::scoped_refptr<RtpSenderInternal> selector,
77                       rtc::scoped_refptr<RTCStatsCollectorCallback> callback);
78   // If `selector` is null the selection algorithm is still applied (interpreted
79   // as: no RTP streams are received by selector). The result is empty.
80   void GetStatsReport(rtc::scoped_refptr<RtpReceiverInternal> selector,
81                       rtc::scoped_refptr<RTCStatsCollectorCallback> callback);
82   // Clears the cache's reference to the most recent stats report. Subsequently
83   // calling `GetStatsReport` guarantees fresh stats. This method must be called
84   // any time the PeerConnection visibly changes as a result of an API call as
85   // per
86   // https://w3c.github.io/webrtc-stats/#guidelines-for-getstats-results-caching-throttling
87   // and it must be called any time negotiation happens.
88   void ClearCachedStatsReport();
89 
90   // If there is a `GetStatsReport` requests in-flight, waits until it has been
91   // completed. Must be called on the signaling thread.
92   void WaitForPendingRequest();
93 
94  protected:
95   RTCStatsCollector(PeerConnectionInternal* pc, int64_t cache_lifetime_us);
96   ~RTCStatsCollector();
97 
98   struct CertificateStatsPair {
99     std::unique_ptr<rtc::SSLCertificateStats> local;
100     std::unique_ptr<rtc::SSLCertificateStats> remote;
101 
102     CertificateStatsPair Copy() const;
103   };
104 
105   // Stats gathering on a particular thread. Virtual for the sake of testing.
106   virtual void ProducePartialResultsOnSignalingThreadImpl(
107       int64_t timestamp_us,
108       RTCStatsReport* partial_report);
109   virtual void ProducePartialResultsOnNetworkThreadImpl(
110       int64_t timestamp_us,
111       const std::map<std::string, cricket::TransportStats>&
112           transport_stats_by_name,
113       const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
114       RTCStatsReport* partial_report);
115 
116  private:
117   class RequestInfo {
118    public:
119     enum class FilterMode { kAll, kSenderSelector, kReceiverSelector };
120 
121     // Constructs with FilterMode::kAll.
122     explicit RequestInfo(
123         rtc::scoped_refptr<RTCStatsCollectorCallback> callback);
124     // Constructs with FilterMode::kSenderSelector. The selection algorithm is
125     // applied even if `selector` is null, resulting in an empty report.
126     RequestInfo(rtc::scoped_refptr<RtpSenderInternal> selector,
127                 rtc::scoped_refptr<RTCStatsCollectorCallback> callback);
128     // Constructs with FilterMode::kReceiverSelector. The selection algorithm is
129     // applied even if `selector` is null, resulting in an empty report.
130     RequestInfo(rtc::scoped_refptr<RtpReceiverInternal> selector,
131                 rtc::scoped_refptr<RTCStatsCollectorCallback> callback);
132 
filter_mode()133     FilterMode filter_mode() const { return filter_mode_; }
callback()134     rtc::scoped_refptr<RTCStatsCollectorCallback> callback() const {
135       return callback_;
136     }
sender_selector()137     rtc::scoped_refptr<RtpSenderInternal> sender_selector() const {
138       RTC_DCHECK(filter_mode_ == FilterMode::kSenderSelector);
139       return sender_selector_;
140     }
receiver_selector()141     rtc::scoped_refptr<RtpReceiverInternal> receiver_selector() const {
142       RTC_DCHECK(filter_mode_ == FilterMode::kReceiverSelector);
143       return receiver_selector_;
144     }
145 
146    private:
147     RequestInfo(FilterMode filter_mode,
148                 rtc::scoped_refptr<RTCStatsCollectorCallback> callback,
149                 rtc::scoped_refptr<RtpSenderInternal> sender_selector,
150                 rtc::scoped_refptr<RtpReceiverInternal> receiver_selector);
151 
152     FilterMode filter_mode_;
153     rtc::scoped_refptr<RTCStatsCollectorCallback> callback_;
154     rtc::scoped_refptr<RtpSenderInternal> sender_selector_;
155     rtc::scoped_refptr<RtpReceiverInternal> receiver_selector_;
156   };
157 
158   void GetStatsReportInternal(RequestInfo request);
159 
160   // Structure for tracking stats about each RtpTransceiver managed by the
161   // PeerConnection. This can either by a Plan B style or Unified Plan style
162   // transceiver (i.e., can have 0 or many senders and receivers).
163   // Some fields are copied from the RtpTransceiver/BaseChannel object so that
164   // they can be accessed safely on threads other than the signaling thread.
165   // If a BaseChannel is not available (e.g., if signaling has not started),
166   // then `mid` and `transport_name` will be null.
167   struct RtpTransceiverStatsInfo {
168     rtc::scoped_refptr<RtpTransceiver> transceiver;
169     cricket::MediaType media_type;
170     absl::optional<std::string> mid;
171     absl::optional<std::string> transport_name;
172     TrackMediaInfoMap track_media_info_map;
173   };
174 
175   void DeliverCachedReport(
176       rtc::scoped_refptr<const RTCStatsReport> cached_report,
177       std::vector<RequestInfo> requests);
178 
179   // Produces `RTCCertificateStats`.
180   void ProduceCertificateStats_n(
181       int64_t timestamp_us,
182       const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
183       RTCStatsReport* report) const;
184   // Produces `RTCDataChannelStats`.
185   void ProduceDataChannelStats_s(int64_t timestamp_us,
186                                  RTCStatsReport* report) const;
187   // Produces `RTCIceCandidatePairStats` and `RTCIceCandidateStats`.
188   void ProduceIceCandidateAndPairStats_n(
189       int64_t timestamp_us,
190       const std::map<std::string, cricket::TransportStats>&
191           transport_stats_by_name,
192       const Call::Stats& call_stats,
193       RTCStatsReport* report) const;
194   // Produces `RTCMediaStreamStats`.
195   void ProduceMediaStreamStats_s(int64_t timestamp_us,
196                                  RTCStatsReport* report) const;
197   // Produces `RTCMediaStreamTrackStats`.
198   void ProduceMediaStreamTrackStats_s(int64_t timestamp_us,
199                                       RTCStatsReport* report) const;
200   // Produces RTCMediaSourceStats, including RTCAudioSourceStats and
201   // RTCVideoSourceStats.
202   void ProduceMediaSourceStats_s(int64_t timestamp_us,
203                                  RTCStatsReport* report) const;
204   // Produces `RTCPeerConnectionStats`.
205   void ProducePeerConnectionStats_s(int64_t timestamp_us,
206                                     RTCStatsReport* report) const;
207   // Produces `RTCInboundRTPStreamStats`, `RTCOutboundRTPStreamStats`,
208   // `RTCRemoteInboundRtpStreamStats`, `RTCRemoteOutboundRtpStreamStats` and any
209   // referenced `RTCCodecStats`. This has to be invoked after transport stats
210   // have been created because some metrics are calculated through lookup of
211   // other metrics.
212   void ProduceRTPStreamStats_n(
213       int64_t timestamp_us,
214       const std::vector<RtpTransceiverStatsInfo>& transceiver_stats_infos,
215       RTCStatsReport* report) const;
216   void ProduceAudioRTPStreamStats_n(int64_t timestamp_us,
217                                     const RtpTransceiverStatsInfo& stats,
218                                     RTCStatsReport* report) const;
219   void ProduceVideoRTPStreamStats_n(int64_t timestamp_us,
220                                     const RtpTransceiverStatsInfo& stats,
221                                     RTCStatsReport* report) const;
222   // Produces `RTCTransportStats`.
223   void ProduceTransportStats_n(
224       int64_t timestamp_us,
225       const std::map<std::string, cricket::TransportStats>&
226           transport_stats_by_name,
227       const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
228       RTCStatsReport* report) const;
229 
230   // Helper function to stats-producing functions.
231   std::map<std::string, CertificateStatsPair>
232   PrepareTransportCertificateStats_n(
233       const std::map<std::string, cricket::TransportStats>&
234           transport_stats_by_name);
235   // The results are stored in `transceiver_stats_infos_` and `call_stats_`.
236   void PrepareTransceiverStatsInfosAndCallStats_s_w_n();
237 
238   // Stats gathering on a particular thread.
239   void ProducePartialResultsOnSignalingThread(int64_t timestamp_us);
240   void ProducePartialResultsOnNetworkThread(
241       int64_t timestamp_us,
242       absl::optional<std::string> sctp_transport_name);
243   // Merges `network_report_` into `partial_report_` and completes the request.
244   // This is a NO-OP if `network_report_` is null.
245   void MergeNetworkReport_s();
246 
247   // Slots for signals (sigslot) that are wired up to `pc_`.
248   void OnSctpDataChannelCreated(SctpDataChannel* channel);
249   // Slots for signals (sigslot) that are wired up to `channel`.
250   void OnDataChannelOpened(DataChannelInterface* channel);
251   void OnDataChannelClosed(DataChannelInterface* channel);
252 
253   PeerConnectionInternal* const pc_;
254   rtc::Thread* const signaling_thread_;
255   rtc::Thread* const worker_thread_;
256   rtc::Thread* const network_thread_;
257 
258   int num_pending_partial_reports_;
259   int64_t partial_report_timestamp_us_;
260   // Reports that are produced on the signaling thread or the network thread are
261   // merged into this report. It is only touched on the signaling thread. Once
262   // all partial reports are merged this is the result of a request.
263   rtc::scoped_refptr<RTCStatsReport> partial_report_;
264   std::vector<RequestInfo> requests_;
265   // Holds the result of ProducePartialResultsOnNetworkThread(). It is merged
266   // into `partial_report_` on the signaling thread and then nulled by
267   // MergeNetworkReport_s(). Thread-safety is ensured by using
268   // `network_report_event_`.
269   rtc::scoped_refptr<RTCStatsReport> network_report_;
270   // If set, it is safe to touch the `network_report_` on the signaling thread.
271   // This is reset before async-invoking ProducePartialResultsOnNetworkThread()
272   // and set when ProducePartialResultsOnNetworkThread() is complete, after it
273   // has updated the value of `network_report_`.
274   rtc::Event network_report_event_;
275 
276   // Cleared and set in `PrepareTransceiverStatsInfosAndCallStats_s_w_n`,
277   // starting out on the signaling thread, then network. Later read on the
278   // network and signaling threads as part of collecting stats and finally
279   // reset when the work is done. Initially this variable was added and not
280   // passed around as an arguments to avoid copies. This is thread safe due to
281   // how operations are sequenced and we don't start the stats collection
282   // sequence if one is in progress. As a future improvement though, we could
283   // now get rid of the variable and keep the data scoped within a stats
284   // collection sequence.
285   std::vector<RtpTransceiverStatsInfo> transceiver_stats_infos_;
286   // This cache avoids having to call rtc::SSLCertChain::GetStats(), which can
287   // relatively expensive. ClearCachedStatsReport() needs to be called on
288   // negotiation to ensure the cache is not obsolete.
289   Mutex cached_certificates_mutex_;
290   std::map<std::string, CertificateStatsPair> cached_certificates_by_transport_
291       RTC_GUARDED_BY(cached_certificates_mutex_);
292 
293   Call::Stats call_stats_;
294 
295   // A timestamp, in microseconds, that is based on a timer that is
296   // monotonically increasing. That is, even if the system clock is modified the
297   // difference between the timer and this timestamp is how fresh the cached
298   // report is.
299   int64_t cache_timestamp_us_;
300   int64_t cache_lifetime_us_;
301   rtc::scoped_refptr<const RTCStatsReport> cached_report_;
302 
303   // Data recorded and maintained by the stats collector during its lifetime.
304   // Some stats are produced from this record instead of other components.
305   struct InternalRecord {
InternalRecordInternalRecord306     InternalRecord() : data_channels_opened(0), data_channels_closed(0) {}
307 
308     // The opened count goes up when a channel is fully opened and the closed
309     // count goes up if a previously opened channel has fully closed. The opened
310     // count does not go down when a channel closes, meaning (opened - closed)
311     // is the number of channels currently opened. A channel that is closed
312     // before reaching the open state does not affect these counters.
313     uint32_t data_channels_opened;
314     uint32_t data_channels_closed;
315     // Identifies by address channels that have been opened, which remain in the
316     // set until they have been fully closed.
317     std::set<uintptr_t> opened_data_channels;
318   };
319   InternalRecord internal_record_;
320 };
321 
322 const char* CandidateTypeToRTCIceCandidateTypeForTesting(
323     const std::string& type);
324 const char* DataStateToRTCDataChannelStateForTesting(
325     DataChannelInterface::DataState state);
326 
327 }  // namespace webrtc
328 
329 #endif  // PC_RTC_STATS_COLLECTOR_H_
330