xref: /aosp_15_r20/external/webrtc/pc/rtc_stats_collector.cc (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 #include "pc/rtc_stats_collector.h"
12 
13 #include <stdint.h>
14 #include <stdio.h>
15 
16 #include <cstdint>
17 #include <map>
18 #include <memory>
19 #include <string>
20 #include <type_traits>
21 #include <utility>
22 #include <vector>
23 
24 #include "absl/functional/bind_front.h"
25 #include "absl/strings/string_view.h"
26 #include "api/array_view.h"
27 #include "api/candidate.h"
28 #include "api/dtls_transport_interface.h"
29 #include "api/media_stream_interface.h"
30 #include "api/rtp_parameters.h"
31 #include "api/sequence_checker.h"
32 #include "api/stats/rtc_stats.h"
33 #include "api/stats/rtcstats_objects.h"
34 #include "api/units/time_delta.h"
35 #include "api/video/video_content_type.h"
36 #include "common_video/include/quality_limitation_reason.h"
37 #include "media/base/media_channel.h"
38 #include "modules/audio_processing/include/audio_processing_statistics.h"
39 #include "modules/rtp_rtcp/include/report_block_data.h"
40 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
41 #include "p2p/base/connection_info.h"
42 #include "p2p/base/ice_transport_internal.h"
43 #include "p2p/base/p2p_constants.h"
44 #include "p2p/base/port.h"
45 #include "pc/channel_interface.h"
46 #include "pc/data_channel_utils.h"
47 #include "pc/rtc_stats_traversal.h"
48 #include "pc/rtp_receiver_proxy.h"
49 #include "pc/rtp_sender_proxy.h"
50 #include "pc/webrtc_sdp.h"
51 #include "rtc_base/checks.h"
52 #include "rtc_base/ip_address.h"
53 #include "rtc_base/logging.h"
54 #include "rtc_base/network_constants.h"
55 #include "rtc_base/rtc_certificate.h"
56 #include "rtc_base/socket_address.h"
57 #include "rtc_base/ssl_stream_adapter.h"
58 #include "rtc_base/string_encode.h"
59 #include "rtc_base/strings/string_builder.h"
60 #include "rtc_base/time_utils.h"
61 #include "rtc_base/trace_event.h"
62 
63 namespace webrtc {
64 
65 namespace {
66 
67 const char kDirectionInbound = 'I';
68 const char kDirectionOutbound = 'O';
69 
70 // TODO(https://crbug.com/webrtc/10656): Consider making IDs less predictable.
RTCCertificateIDFromFingerprint(const std::string & fingerprint)71 std::string RTCCertificateIDFromFingerprint(const std::string& fingerprint) {
72   return "CF" + fingerprint;
73 }
74 
75 // `direction` is either kDirectionInbound or kDirectionOutbound.
RTCCodecStatsIDFromTransportAndCodecParameters(const char direction,const std::string & transport_id,const RtpCodecParameters & codec_params)76 std::string RTCCodecStatsIDFromTransportAndCodecParameters(
77     const char direction,
78     const std::string& transport_id,
79     const RtpCodecParameters& codec_params) {
80   char buf[1024];
81   rtc::SimpleStringBuilder sb(buf);
82   sb << 'C' << direction << transport_id << '_' << codec_params.payload_type;
83   // TODO(https://crbug.com/webrtc/14420): If we stop supporting different FMTP
84   // lines for the same PT and transport, which should be illegal SDP, then we
85   // wouldn't need `fmtp` to be part of the ID here.
86   rtc::StringBuilder fmtp;
87   if (WriteFmtpParameters(codec_params.parameters, &fmtp)) {
88     sb << '_' << fmtp.Release();
89   }
90   return sb.str();
91 }
92 
RTCIceCandidatePairStatsIDFromConnectionInfo(const cricket::ConnectionInfo & info)93 std::string RTCIceCandidatePairStatsIDFromConnectionInfo(
94     const cricket::ConnectionInfo& info) {
95   char buf[4096];
96   rtc::SimpleStringBuilder sb(buf);
97   sb << "CP" << info.local_candidate.id() << "_" << info.remote_candidate.id();
98   return sb.str();
99 }
100 
101 // `direction` is either kDirectionInbound or kDirectionOutbound.
DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(const char direction,int attachment_id)102 std::string DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
103     const char direction,
104     int attachment_id) {
105   char buf[1024];
106   rtc::SimpleStringBuilder sb(buf);
107   sb << "DEPRECATED_T" << direction << attachment_id;
108   return sb.str();
109 }
110 
RTCTransportStatsIDFromTransportChannel(const std::string & transport_name,int channel_component)111 std::string RTCTransportStatsIDFromTransportChannel(
112     const std::string& transport_name,
113     int channel_component) {
114   char buf[1024];
115   rtc::SimpleStringBuilder sb(buf);
116   sb << 'T' << transport_name << channel_component;
117   return sb.str();
118 }
119 
RTCInboundRTPStreamStatsIDFromSSRC(const std::string & transport_id,cricket::MediaType media_type,uint32_t ssrc)120 std::string RTCInboundRTPStreamStatsIDFromSSRC(const std::string& transport_id,
121                                                cricket::MediaType media_type,
122                                                uint32_t ssrc) {
123   char buf[1024];
124   rtc::SimpleStringBuilder sb(buf);
125   sb << 'I' << transport_id
126      << (media_type == cricket::MEDIA_TYPE_AUDIO ? 'A' : 'V') << ssrc;
127   return sb.str();
128 }
129 
RTCOutboundRTPStreamStatsIDFromSSRC(const std::string & transport_id,cricket::MediaType media_type,uint32_t ssrc)130 std::string RTCOutboundRTPStreamStatsIDFromSSRC(const std::string& transport_id,
131                                                 cricket::MediaType media_type,
132                                                 uint32_t ssrc) {
133   char buf[1024];
134   rtc::SimpleStringBuilder sb(buf);
135   sb << 'O' << transport_id
136      << (media_type == cricket::MEDIA_TYPE_AUDIO ? 'A' : 'V') << ssrc;
137   return sb.str();
138 }
139 
RTCRemoteInboundRtpStreamStatsIdFromSourceSsrc(cricket::MediaType media_type,uint32_t source_ssrc)140 std::string RTCRemoteInboundRtpStreamStatsIdFromSourceSsrc(
141     cricket::MediaType media_type,
142     uint32_t source_ssrc) {
143   char buf[1024];
144   rtc::SimpleStringBuilder sb(buf);
145   sb << "RI" << (media_type == cricket::MEDIA_TYPE_AUDIO ? 'A' : 'V')
146      << source_ssrc;
147   return sb.str();
148 }
149 
RTCRemoteOutboundRTPStreamStatsIDFromSSRC(cricket::MediaType media_type,uint32_t source_ssrc)150 std::string RTCRemoteOutboundRTPStreamStatsIDFromSSRC(
151     cricket::MediaType media_type,
152     uint32_t source_ssrc) {
153   char buf[1024];
154   rtc::SimpleStringBuilder sb(buf);
155   sb << "RO" << (media_type == cricket::MEDIA_TYPE_AUDIO ? 'A' : 'V')
156      << source_ssrc;
157   return sb.str();
158 }
159 
RTCMediaSourceStatsIDFromKindAndAttachment(cricket::MediaType media_type,int attachment_id)160 std::string RTCMediaSourceStatsIDFromKindAndAttachment(
161     cricket::MediaType media_type,
162     int attachment_id) {
163   char buf[1024];
164   rtc::SimpleStringBuilder sb(buf);
165   sb << 'S' << (media_type == cricket::MEDIA_TYPE_AUDIO ? 'A' : 'V')
166      << attachment_id;
167   return sb.str();
168 }
169 
CandidateTypeToRTCIceCandidateType(const std::string & type)170 const char* CandidateTypeToRTCIceCandidateType(const std::string& type) {
171   if (type == cricket::LOCAL_PORT_TYPE)
172     return RTCIceCandidateType::kHost;
173   if (type == cricket::STUN_PORT_TYPE)
174     return RTCIceCandidateType::kSrflx;
175   if (type == cricket::PRFLX_PORT_TYPE)
176     return RTCIceCandidateType::kPrflx;
177   if (type == cricket::RELAY_PORT_TYPE)
178     return RTCIceCandidateType::kRelay;
179   RTC_DCHECK_NOTREACHED();
180   return nullptr;
181 }
182 
DataStateToRTCDataChannelState(DataChannelInterface::DataState state)183 const char* DataStateToRTCDataChannelState(
184     DataChannelInterface::DataState state) {
185   switch (state) {
186     case DataChannelInterface::kConnecting:
187       return RTCDataChannelState::kConnecting;
188     case DataChannelInterface::kOpen:
189       return RTCDataChannelState::kOpen;
190     case DataChannelInterface::kClosing:
191       return RTCDataChannelState::kClosing;
192     case DataChannelInterface::kClosed:
193       return RTCDataChannelState::kClosed;
194     default:
195       RTC_DCHECK_NOTREACHED();
196       return nullptr;
197   }
198 }
199 
IceCandidatePairStateToRTCStatsIceCandidatePairState(cricket::IceCandidatePairState state)200 const char* IceCandidatePairStateToRTCStatsIceCandidatePairState(
201     cricket::IceCandidatePairState state) {
202   switch (state) {
203     case cricket::IceCandidatePairState::WAITING:
204       return RTCStatsIceCandidatePairState::kWaiting;
205     case cricket::IceCandidatePairState::IN_PROGRESS:
206       return RTCStatsIceCandidatePairState::kInProgress;
207     case cricket::IceCandidatePairState::SUCCEEDED:
208       return RTCStatsIceCandidatePairState::kSucceeded;
209     case cricket::IceCandidatePairState::FAILED:
210       return RTCStatsIceCandidatePairState::kFailed;
211     default:
212       RTC_DCHECK_NOTREACHED();
213       return nullptr;
214   }
215 }
216 
IceRoleToRTCIceRole(cricket::IceRole role)217 const char* IceRoleToRTCIceRole(cricket::IceRole role) {
218   switch (role) {
219     case cricket::IceRole::ICEROLE_UNKNOWN:
220       return RTCIceRole::kUnknown;
221     case cricket::IceRole::ICEROLE_CONTROLLED:
222       return RTCIceRole::kControlled;
223     case cricket::IceRole::ICEROLE_CONTROLLING:
224       return RTCIceRole::kControlling;
225     default:
226       RTC_DCHECK_NOTREACHED();
227       return nullptr;
228   }
229 }
230 
DtlsTransportStateToRTCDtlsTransportState(DtlsTransportState state)231 const char* DtlsTransportStateToRTCDtlsTransportState(
232     DtlsTransportState state) {
233   switch (state) {
234     case DtlsTransportState::kNew:
235       return RTCDtlsTransportState::kNew;
236     case DtlsTransportState::kConnecting:
237       return RTCDtlsTransportState::kConnecting;
238     case DtlsTransportState::kConnected:
239       return RTCDtlsTransportState::kConnected;
240     case DtlsTransportState::kClosed:
241       return RTCDtlsTransportState::kClosed;
242     case DtlsTransportState::kFailed:
243       return RTCDtlsTransportState::kFailed;
244     default:
245       RTC_CHECK_NOTREACHED();
246       return nullptr;
247   }
248 }
249 
IceTransportStateToRTCIceTransportState(IceTransportState state)250 const char* IceTransportStateToRTCIceTransportState(IceTransportState state) {
251   switch (state) {
252     case IceTransportState::kNew:
253       return RTCIceTransportState::kNew;
254     case IceTransportState::kChecking:
255       return RTCIceTransportState::kChecking;
256     case IceTransportState::kConnected:
257       return RTCIceTransportState::kConnected;
258     case IceTransportState::kCompleted:
259       return RTCIceTransportState::kCompleted;
260     case IceTransportState::kFailed:
261       return RTCIceTransportState::kFailed;
262     case IceTransportState::kDisconnected:
263       return RTCIceTransportState::kDisconnected;
264     case IceTransportState::kClosed:
265       return RTCIceTransportState::kClosed;
266     default:
267       RTC_CHECK_NOTREACHED();
268       return nullptr;
269   }
270 }
271 
NetworkTypeToStatsType(rtc::AdapterType type)272 const char* NetworkTypeToStatsType(rtc::AdapterType type) {
273   switch (type) {
274     case rtc::ADAPTER_TYPE_CELLULAR:
275     case rtc::ADAPTER_TYPE_CELLULAR_2G:
276     case rtc::ADAPTER_TYPE_CELLULAR_3G:
277     case rtc::ADAPTER_TYPE_CELLULAR_4G:
278     case rtc::ADAPTER_TYPE_CELLULAR_5G:
279       return RTCNetworkType::kCellular;
280     case rtc::ADAPTER_TYPE_ETHERNET:
281       return RTCNetworkType::kEthernet;
282     case rtc::ADAPTER_TYPE_WIFI:
283       return RTCNetworkType::kWifi;
284     case rtc::ADAPTER_TYPE_VPN:
285       return RTCNetworkType::kVpn;
286     case rtc::ADAPTER_TYPE_UNKNOWN:
287     case rtc::ADAPTER_TYPE_LOOPBACK:
288     case rtc::ADAPTER_TYPE_ANY:
289       return RTCNetworkType::kUnknown;
290   }
291   RTC_DCHECK_NOTREACHED();
292   return nullptr;
293 }
294 
NetworkTypeToStatsNetworkAdapterType(rtc::AdapterType type)295 absl::string_view NetworkTypeToStatsNetworkAdapterType(rtc::AdapterType type) {
296   switch (type) {
297     case rtc::ADAPTER_TYPE_CELLULAR:
298       return RTCNetworkAdapterType::kCellular;
299     case rtc::ADAPTER_TYPE_CELLULAR_2G:
300       return RTCNetworkAdapterType::kCellular2g;
301     case rtc::ADAPTER_TYPE_CELLULAR_3G:
302       return RTCNetworkAdapterType::kCellular3g;
303     case rtc::ADAPTER_TYPE_CELLULAR_4G:
304       return RTCNetworkAdapterType::kCellular4g;
305     case rtc::ADAPTER_TYPE_CELLULAR_5G:
306       return RTCNetworkAdapterType::kCellular5g;
307     case rtc::ADAPTER_TYPE_ETHERNET:
308       return RTCNetworkAdapterType::kEthernet;
309     case rtc::ADAPTER_TYPE_WIFI:
310       return RTCNetworkAdapterType::kWifi;
311     case rtc::ADAPTER_TYPE_UNKNOWN:
312       return RTCNetworkAdapterType::kUnknown;
313     case rtc::ADAPTER_TYPE_LOOPBACK:
314       return RTCNetworkAdapterType::kLoopback;
315     case rtc::ADAPTER_TYPE_ANY:
316       return RTCNetworkAdapterType::kAny;
317     case rtc::ADAPTER_TYPE_VPN:
318       /* should not be handled here. Vpn is modelled as a bool */
319       break;
320   }
321   RTC_DCHECK_NOTREACHED();
322   return {};
323 }
324 
QualityLimitationReasonToRTCQualityLimitationReason(QualityLimitationReason reason)325 const char* QualityLimitationReasonToRTCQualityLimitationReason(
326     QualityLimitationReason reason) {
327   switch (reason) {
328     case QualityLimitationReason::kNone:
329       return RTCQualityLimitationReason::kNone;
330     case QualityLimitationReason::kCpu:
331       return RTCQualityLimitationReason::kCpu;
332     case QualityLimitationReason::kBandwidth:
333       return RTCQualityLimitationReason::kBandwidth;
334     case QualityLimitationReason::kOther:
335       return RTCQualityLimitationReason::kOther;
336   }
337   RTC_CHECK_NOTREACHED();
338 }
339 
340 std::map<std::string, double>
QualityLimitationDurationToRTCQualityLimitationDuration(std::map<webrtc::QualityLimitationReason,int64_t> durations_ms)341 QualityLimitationDurationToRTCQualityLimitationDuration(
342     std::map<webrtc::QualityLimitationReason, int64_t> durations_ms) {
343   std::map<std::string, double> result;
344   // The internal duration is defined in milliseconds while the spec defines
345   // the value in seconds:
346   // https://w3c.github.io/webrtc-stats/#dom-rtcoutboundrtpstreamstats-qualitylimitationdurations
347   for (const auto& elem : durations_ms) {
348     result[QualityLimitationReasonToRTCQualityLimitationReason(elem.first)] =
349         elem.second / static_cast<double>(rtc::kNumMillisecsPerSec);
350   }
351   return result;
352 }
353 
DoubleAudioLevelFromIntAudioLevel(int audio_level)354 double DoubleAudioLevelFromIntAudioLevel(int audio_level) {
355   RTC_DCHECK_GE(audio_level, 0);
356   RTC_DCHECK_LE(audio_level, 32767);
357   return audio_level / 32767.0;
358 }
359 
360 // Gets the `codecId` identified by `transport_id` and `codec_params`. If no
361 // such `RTCCodecStats` exist yet, create it and add it to `report`.
GetCodecIdAndMaybeCreateCodecStats(uint64_t timestamp_us,const char direction,const std::string & transport_id,const RtpCodecParameters & codec_params,RTCStatsReport * report)362 std::string GetCodecIdAndMaybeCreateCodecStats(
363     uint64_t timestamp_us,
364     const char direction,
365     const std::string& transport_id,
366     const RtpCodecParameters& codec_params,
367     RTCStatsReport* report) {
368   RTC_DCHECK_GE(codec_params.payload_type, 0);
369   RTC_DCHECK_LE(codec_params.payload_type, 127);
370   RTC_DCHECK(codec_params.clock_rate);
371   uint32_t payload_type = static_cast<uint32_t>(codec_params.payload_type);
372   std::string codec_id = RTCCodecStatsIDFromTransportAndCodecParameters(
373       direction, transport_id, codec_params);
374   if (report->Get(codec_id) != nullptr) {
375     // The `RTCCodecStats` already exists.
376     return codec_id;
377   }
378   // Create the `RTCCodecStats` that we want to reference.
379   std::unique_ptr<RTCCodecStats> codec_stats(
380       std::make_unique<RTCCodecStats>(codec_id, timestamp_us));
381   codec_stats->payload_type = payload_type;
382   codec_stats->mime_type = codec_params.mime_type();
383   if (codec_params.clock_rate.has_value()) {
384     codec_stats->clock_rate = static_cast<uint32_t>(*codec_params.clock_rate);
385   }
386   if (codec_params.num_channels) {
387     codec_stats->channels = *codec_params.num_channels;
388   }
389 
390   rtc::StringBuilder fmtp;
391   if (WriteFmtpParameters(codec_params.parameters, &fmtp)) {
392     codec_stats->sdp_fmtp_line = fmtp.Release();
393   }
394   codec_stats->transport_id = transport_id;
395   report->AddStats(std::move(codec_stats));
396   return codec_id;
397 }
398 
SetMediaStreamTrackStatsFromMediaStreamTrackInterface(const MediaStreamTrackInterface & track,DEPRECATED_RTCMediaStreamTrackStats * track_stats)399 void SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
400     const MediaStreamTrackInterface& track,
401     DEPRECATED_RTCMediaStreamTrackStats* track_stats) {
402   track_stats->track_identifier = track.id();
403   track_stats->ended = (track.state() == MediaStreamTrackInterface::kEnded);
404 }
405 
406 // Provides the media independent counters (both audio and video).
SetInboundRTPStreamStatsFromMediaReceiverInfo(const cricket::MediaReceiverInfo & media_receiver_info,RTCInboundRTPStreamStats * inbound_stats)407 void SetInboundRTPStreamStatsFromMediaReceiverInfo(
408     const cricket::MediaReceiverInfo& media_receiver_info,
409     RTCInboundRTPStreamStats* inbound_stats) {
410   RTC_DCHECK(inbound_stats);
411   inbound_stats->ssrc = media_receiver_info.ssrc();
412   inbound_stats->packets_received =
413       static_cast<uint32_t>(media_receiver_info.packets_rcvd);
414   inbound_stats->bytes_received =
415       static_cast<uint64_t>(media_receiver_info.payload_bytes_rcvd);
416   inbound_stats->header_bytes_received =
417       static_cast<uint64_t>(media_receiver_info.header_and_padding_bytes_rcvd);
418   inbound_stats->packets_lost =
419       static_cast<int32_t>(media_receiver_info.packets_lost);
420   inbound_stats->jitter_buffer_delay =
421       media_receiver_info.jitter_buffer_delay_seconds;
422   if (media_receiver_info.jitter_buffer_target_delay_seconds.has_value()) {
423     inbound_stats->jitter_buffer_target_delay =
424         *media_receiver_info.jitter_buffer_target_delay_seconds;
425   }
426   if (media_receiver_info.jitter_buffer_minimum_delay_seconds.has_value()) {
427     inbound_stats->jitter_buffer_minimum_delay =
428         *media_receiver_info.jitter_buffer_minimum_delay_seconds;
429   }
430   inbound_stats->jitter_buffer_emitted_count =
431       media_receiver_info.jitter_buffer_emitted_count;
432   if (media_receiver_info.nacks_sent.has_value()) {
433     inbound_stats->nack_count = *media_receiver_info.nacks_sent;
434   }
435 }
436 
CreateInboundAudioStreamStats(const cricket::VoiceMediaInfo & voice_media_info,const cricket::VoiceReceiverInfo & voice_receiver_info,const std::string & transport_id,const std::string & mid,int64_t timestamp_us,RTCStatsReport * report)437 std::unique_ptr<RTCInboundRTPStreamStats> CreateInboundAudioStreamStats(
438     const cricket::VoiceMediaInfo& voice_media_info,
439     const cricket::VoiceReceiverInfo& voice_receiver_info,
440     const std::string& transport_id,
441     const std::string& mid,
442     int64_t timestamp_us,
443     RTCStatsReport* report) {
444   auto inbound_audio = std::make_unique<RTCInboundRTPStreamStats>(
445       /*id=*/RTCInboundRTPStreamStatsIDFromSSRC(
446           transport_id, cricket::MEDIA_TYPE_AUDIO, voice_receiver_info.ssrc()),
447       timestamp_us);
448   SetInboundRTPStreamStatsFromMediaReceiverInfo(voice_receiver_info,
449                                                 inbound_audio.get());
450   inbound_audio->transport_id = transport_id;
451   inbound_audio->mid = mid;
452   inbound_audio->media_type = "audio";
453   inbound_audio->kind = "audio";
454   if (voice_receiver_info.codec_payload_type.has_value()) {
455     auto codec_param_it = voice_media_info.receive_codecs.find(
456         voice_receiver_info.codec_payload_type.value());
457     RTC_DCHECK(codec_param_it != voice_media_info.receive_codecs.end());
458     if (codec_param_it != voice_media_info.receive_codecs.end()) {
459       inbound_audio->codec_id = GetCodecIdAndMaybeCreateCodecStats(
460           inbound_audio->timestamp_us(), kDirectionInbound, transport_id,
461           codec_param_it->second, report);
462     }
463   }
464   inbound_audio->jitter = static_cast<double>(voice_receiver_info.jitter_ms) /
465                           rtc::kNumMillisecsPerSec;
466   inbound_audio->total_samples_received =
467       voice_receiver_info.total_samples_received;
468   inbound_audio->concealed_samples = voice_receiver_info.concealed_samples;
469   inbound_audio->silent_concealed_samples =
470       voice_receiver_info.silent_concealed_samples;
471   inbound_audio->concealment_events = voice_receiver_info.concealment_events;
472   inbound_audio->inserted_samples_for_deceleration =
473       voice_receiver_info.inserted_samples_for_deceleration;
474   inbound_audio->removed_samples_for_acceleration =
475       voice_receiver_info.removed_samples_for_acceleration;
476   if (voice_receiver_info.audio_level >= 0) {
477     inbound_audio->audio_level =
478         DoubleAudioLevelFromIntAudioLevel(voice_receiver_info.audio_level);
479   }
480   inbound_audio->total_audio_energy = voice_receiver_info.total_output_energy;
481   inbound_audio->total_samples_duration =
482       voice_receiver_info.total_output_duration;
483   // `fir_count`, `pli_count` and `sli_count` are only valid for video and are
484   // purposefully left undefined for audio.
485   if (voice_receiver_info.last_packet_received_timestamp_ms.has_value()) {
486     inbound_audio->last_packet_received_timestamp = static_cast<double>(
487         *voice_receiver_info.last_packet_received_timestamp_ms);
488   }
489   if (voice_receiver_info.estimated_playout_ntp_timestamp_ms.has_value()) {
490     // TODO(bugs.webrtc.org/10529): Fix time origin.
491     inbound_audio->estimated_playout_timestamp = static_cast<double>(
492         *voice_receiver_info.estimated_playout_ntp_timestamp_ms);
493   }
494   inbound_audio->fec_packets_received =
495       voice_receiver_info.fec_packets_received;
496   inbound_audio->fec_packets_discarded =
497       voice_receiver_info.fec_packets_discarded;
498   inbound_audio->packets_discarded = voice_receiver_info.packets_discarded;
499   inbound_audio->jitter_buffer_flushes =
500       voice_receiver_info.jitter_buffer_flushes;
501   inbound_audio->delayed_packet_outage_samples =
502       voice_receiver_info.delayed_packet_outage_samples;
503   inbound_audio->relative_packet_arrival_delay =
504       voice_receiver_info.relative_packet_arrival_delay_seconds;
505   inbound_audio->interruption_count =
506       voice_receiver_info.interruption_count >= 0
507           ? voice_receiver_info.interruption_count
508           : 0;
509   inbound_audio->total_interruption_duration =
510       static_cast<double>(voice_receiver_info.total_interruption_duration_ms) /
511       rtc::kNumMillisecsPerSec;
512   return inbound_audio;
513 }
514 
515 std::unique_ptr<RTCRemoteOutboundRtpStreamStats>
CreateRemoteOutboundAudioStreamStats(const cricket::VoiceReceiverInfo & voice_receiver_info,const std::string & mid,const RTCInboundRTPStreamStats & inbound_audio_stats,const std::string & transport_id)516 CreateRemoteOutboundAudioStreamStats(
517     const cricket::VoiceReceiverInfo& voice_receiver_info,
518     const std::string& mid,
519     const RTCInboundRTPStreamStats& inbound_audio_stats,
520     const std::string& transport_id) {
521   if (!voice_receiver_info.last_sender_report_timestamp_ms.has_value()) {
522     // Cannot create `RTCRemoteOutboundRtpStreamStats` when the RTCP SR arrival
523     // timestamp is not available - i.e., until the first sender report is
524     // received.
525     return nullptr;
526   }
527   RTC_DCHECK_GT(voice_receiver_info.sender_reports_reports_count, 0);
528 
529   // Create.
530   auto stats = std::make_unique<RTCRemoteOutboundRtpStreamStats>(
531       /*id=*/RTCRemoteOutboundRTPStreamStatsIDFromSSRC(
532           cricket::MEDIA_TYPE_AUDIO, voice_receiver_info.ssrc()),
533       /*timestamp_us=*/rtc::kNumMicrosecsPerMillisec *
534           voice_receiver_info.last_sender_report_timestamp_ms.value());
535 
536   // Populate.
537   // - RTCRtpStreamStats.
538   stats->ssrc = voice_receiver_info.ssrc();
539   stats->kind = "audio";
540   stats->transport_id = transport_id;
541   if (inbound_audio_stats.codec_id.is_defined()) {
542     stats->codec_id = *inbound_audio_stats.codec_id;
543   }
544   // - RTCSentRtpStreamStats.
545   stats->packets_sent = voice_receiver_info.sender_reports_packets_sent;
546   stats->bytes_sent = voice_receiver_info.sender_reports_bytes_sent;
547   // - RTCRemoteOutboundRtpStreamStats.
548   stats->local_id = inbound_audio_stats.id();
549   RTC_DCHECK(
550       voice_receiver_info.last_sender_report_remote_timestamp_ms.has_value());
551   stats->remote_timestamp = static_cast<double>(
552       voice_receiver_info.last_sender_report_remote_timestamp_ms.value());
553   stats->reports_sent = voice_receiver_info.sender_reports_reports_count;
554   if (voice_receiver_info.round_trip_time.has_value()) {
555     stats->round_trip_time =
556         voice_receiver_info.round_trip_time->seconds<double>();
557   }
558   stats->round_trip_time_measurements =
559       voice_receiver_info.round_trip_time_measurements;
560   stats->total_round_trip_time =
561       voice_receiver_info.total_round_trip_time.seconds<double>();
562 
563   return stats;
564 }
565 
SetInboundRTPStreamStatsFromVideoReceiverInfo(const std::string & transport_id,const std::string & mid,const cricket::VideoMediaInfo & video_media_info,const cricket::VideoReceiverInfo & video_receiver_info,RTCInboundRTPStreamStats * inbound_video,RTCStatsReport * report)566 void SetInboundRTPStreamStatsFromVideoReceiverInfo(
567     const std::string& transport_id,
568     const std::string& mid,
569     const cricket::VideoMediaInfo& video_media_info,
570     const cricket::VideoReceiverInfo& video_receiver_info,
571     RTCInboundRTPStreamStats* inbound_video,
572     RTCStatsReport* report) {
573   SetInboundRTPStreamStatsFromMediaReceiverInfo(video_receiver_info,
574                                                 inbound_video);
575   inbound_video->transport_id = transport_id;
576   inbound_video->mid = mid;
577   inbound_video->media_type = "video";
578   inbound_video->kind = "video";
579   if (video_receiver_info.codec_payload_type.has_value()) {
580     auto codec_param_it = video_media_info.receive_codecs.find(
581         video_receiver_info.codec_payload_type.value());
582     RTC_DCHECK(codec_param_it != video_media_info.receive_codecs.end());
583     if (codec_param_it != video_media_info.receive_codecs.end()) {
584       inbound_video->codec_id = GetCodecIdAndMaybeCreateCodecStats(
585           inbound_video->timestamp_us(), kDirectionInbound, transport_id,
586           codec_param_it->second, report);
587     }
588   }
589   inbound_video->jitter = static_cast<double>(video_receiver_info.jitter_ms) /
590                           rtc::kNumMillisecsPerSec;
591   inbound_video->fir_count =
592       static_cast<uint32_t>(video_receiver_info.firs_sent);
593   inbound_video->pli_count =
594       static_cast<uint32_t>(video_receiver_info.plis_sent);
595   inbound_video->frames_received = video_receiver_info.frames_received;
596   inbound_video->frames_decoded = video_receiver_info.frames_decoded;
597   inbound_video->frames_dropped = video_receiver_info.frames_dropped;
598   inbound_video->key_frames_decoded = video_receiver_info.key_frames_decoded;
599   if (video_receiver_info.frame_width > 0) {
600     inbound_video->frame_width =
601         static_cast<uint32_t>(video_receiver_info.frame_width);
602   }
603   if (video_receiver_info.frame_height > 0) {
604     inbound_video->frame_height =
605         static_cast<uint32_t>(video_receiver_info.frame_height);
606   }
607   if (video_receiver_info.framerate_decoded > 0) {
608     inbound_video->frames_per_second = video_receiver_info.framerate_decoded;
609   }
610   if (video_receiver_info.qp_sum.has_value()) {
611     inbound_video->qp_sum = *video_receiver_info.qp_sum;
612   }
613   if (video_receiver_info.timing_frame_info.has_value()) {
614     inbound_video->goog_timing_frame_info =
615         video_receiver_info.timing_frame_info->ToString();
616   }
617   inbound_video->total_decode_time =
618       video_receiver_info.total_decode_time.seconds<double>();
619   inbound_video->total_processing_delay =
620       video_receiver_info.total_processing_delay.seconds<double>();
621   inbound_video->total_assembly_time =
622       video_receiver_info.total_assembly_time.seconds<double>();
623   inbound_video->frames_assembled_from_multiple_packets =
624       video_receiver_info.frames_assembled_from_multiple_packets;
625   inbound_video->total_inter_frame_delay =
626       video_receiver_info.total_inter_frame_delay;
627   inbound_video->total_squared_inter_frame_delay =
628       video_receiver_info.total_squared_inter_frame_delay;
629   inbound_video->pause_count = video_receiver_info.pause_count;
630   inbound_video->total_pauses_duration =
631       static_cast<double>(video_receiver_info.total_pauses_duration_ms) /
632       rtc::kNumMillisecsPerSec;
633   inbound_video->freeze_count = video_receiver_info.freeze_count;
634   inbound_video->total_freezes_duration =
635       static_cast<double>(video_receiver_info.total_freezes_duration_ms) /
636       rtc::kNumMillisecsPerSec;
637   inbound_video->min_playout_delay =
638       static_cast<double>(video_receiver_info.min_playout_delay_ms) /
639       rtc::kNumMillisecsPerSec;
640   if (video_receiver_info.last_packet_received_timestamp_ms.has_value()) {
641     inbound_video->last_packet_received_timestamp = static_cast<double>(
642         *video_receiver_info.last_packet_received_timestamp_ms);
643   }
644   if (video_receiver_info.estimated_playout_ntp_timestamp_ms.has_value()) {
645     // TODO(bugs.webrtc.org/10529): Fix time origin if needed.
646     inbound_video->estimated_playout_timestamp = static_cast<double>(
647         *video_receiver_info.estimated_playout_ntp_timestamp_ms);
648   }
649   // TODO(bugs.webrtc.org/10529): When info's `content_info` is optional
650   // support the "unspecified" value.
651   if (video_receiver_info.content_type == VideoContentType::SCREENSHARE)
652     inbound_video->content_type = RTCContentType::kScreenshare;
653   if (!video_receiver_info.decoder_implementation_name.empty()) {
654     inbound_video->decoder_implementation =
655         video_receiver_info.decoder_implementation_name;
656   }
657   if (video_receiver_info.power_efficient_decoder.has_value()) {
658     inbound_video->power_efficient_decoder =
659         video_receiver_info.power_efficient_decoder.value();
660   }
661 }
662 
663 // Provides the media independent counters and information (both audio and
664 // video).
SetOutboundRTPStreamStatsFromMediaSenderInfo(const cricket::MediaSenderInfo & media_sender_info,RTCOutboundRTPStreamStats * outbound_stats)665 void SetOutboundRTPStreamStatsFromMediaSenderInfo(
666     const cricket::MediaSenderInfo& media_sender_info,
667     RTCOutboundRTPStreamStats* outbound_stats) {
668   RTC_DCHECK(outbound_stats);
669   outbound_stats->ssrc = media_sender_info.ssrc();
670   outbound_stats->packets_sent =
671       static_cast<uint32_t>(media_sender_info.packets_sent);
672   outbound_stats->total_packet_send_delay =
673       media_sender_info.total_packet_send_delay.seconds<double>();
674   outbound_stats->retransmitted_packets_sent =
675       media_sender_info.retransmitted_packets_sent;
676   outbound_stats->bytes_sent =
677       static_cast<uint64_t>(media_sender_info.payload_bytes_sent);
678   outbound_stats->header_bytes_sent =
679       static_cast<uint64_t>(media_sender_info.header_and_padding_bytes_sent);
680   outbound_stats->retransmitted_bytes_sent =
681       media_sender_info.retransmitted_bytes_sent;
682   outbound_stats->nack_count = media_sender_info.nacks_rcvd;
683   if (media_sender_info.active.has_value()) {
684     outbound_stats->active = *media_sender_info.active;
685   }
686 }
687 
SetOutboundRTPStreamStatsFromVoiceSenderInfo(const std::string & transport_id,const std::string & mid,const cricket::VoiceMediaInfo & voice_media_info,const cricket::VoiceSenderInfo & voice_sender_info,RTCOutboundRTPStreamStats * outbound_audio,RTCStatsReport * report)688 void SetOutboundRTPStreamStatsFromVoiceSenderInfo(
689     const std::string& transport_id,
690     const std::string& mid,
691     const cricket::VoiceMediaInfo& voice_media_info,
692     const cricket::VoiceSenderInfo& voice_sender_info,
693     RTCOutboundRTPStreamStats* outbound_audio,
694     RTCStatsReport* report) {
695   SetOutboundRTPStreamStatsFromMediaSenderInfo(voice_sender_info,
696                                                outbound_audio);
697   outbound_audio->transport_id = transport_id;
698   outbound_audio->mid = mid;
699   outbound_audio->media_type = "audio";
700   outbound_audio->kind = "audio";
701   if (voice_sender_info.target_bitrate.has_value() &&
702       *voice_sender_info.target_bitrate > 0) {
703     outbound_audio->target_bitrate = *voice_sender_info.target_bitrate;
704   }
705   if (voice_sender_info.codec_payload_type.has_value()) {
706     auto codec_param_it = voice_media_info.send_codecs.find(
707         voice_sender_info.codec_payload_type.value());
708     RTC_DCHECK(codec_param_it != voice_media_info.send_codecs.end());
709     if (codec_param_it != voice_media_info.send_codecs.end()) {
710       outbound_audio->codec_id = GetCodecIdAndMaybeCreateCodecStats(
711           outbound_audio->timestamp_us(), kDirectionOutbound, transport_id,
712           codec_param_it->second, report);
713     }
714   }
715   // `fir_count`, `pli_count` and `sli_count` are only valid for video and are
716   // purposefully left undefined for audio.
717 }
718 
SetOutboundRTPStreamStatsFromVideoSenderInfo(const std::string & transport_id,const std::string & mid,const cricket::VideoMediaInfo & video_media_info,const cricket::VideoSenderInfo & video_sender_info,RTCOutboundRTPStreamStats * outbound_video,RTCStatsReport * report)719 void SetOutboundRTPStreamStatsFromVideoSenderInfo(
720     const std::string& transport_id,
721     const std::string& mid,
722     const cricket::VideoMediaInfo& video_media_info,
723     const cricket::VideoSenderInfo& video_sender_info,
724     RTCOutboundRTPStreamStats* outbound_video,
725     RTCStatsReport* report) {
726   SetOutboundRTPStreamStatsFromMediaSenderInfo(video_sender_info,
727                                                outbound_video);
728   outbound_video->transport_id = transport_id;
729   outbound_video->mid = mid;
730   outbound_video->media_type = "video";
731   outbound_video->kind = "video";
732   if (video_sender_info.codec_payload_type.has_value()) {
733     auto codec_param_it = video_media_info.send_codecs.find(
734         video_sender_info.codec_payload_type.value());
735     RTC_DCHECK(codec_param_it != video_media_info.send_codecs.end());
736     if (codec_param_it != video_media_info.send_codecs.end()) {
737       outbound_video->codec_id = GetCodecIdAndMaybeCreateCodecStats(
738           outbound_video->timestamp_us(), kDirectionOutbound, transport_id,
739           codec_param_it->second, report);
740     }
741   }
742   outbound_video->fir_count =
743       static_cast<uint32_t>(video_sender_info.firs_rcvd);
744   outbound_video->pli_count =
745       static_cast<uint32_t>(video_sender_info.plis_rcvd);
746   if (video_sender_info.qp_sum.has_value())
747     outbound_video->qp_sum = *video_sender_info.qp_sum;
748   if (video_sender_info.target_bitrate.has_value() &&
749       *video_sender_info.target_bitrate > 0) {
750     outbound_video->target_bitrate = *video_sender_info.target_bitrate;
751   }
752   outbound_video->frames_encoded = video_sender_info.frames_encoded;
753   outbound_video->key_frames_encoded = video_sender_info.key_frames_encoded;
754   outbound_video->total_encode_time =
755       static_cast<double>(video_sender_info.total_encode_time_ms) /
756       rtc::kNumMillisecsPerSec;
757   outbound_video->total_encoded_bytes_target =
758       video_sender_info.total_encoded_bytes_target;
759   if (video_sender_info.send_frame_width > 0) {
760     outbound_video->frame_width =
761         static_cast<uint32_t>(video_sender_info.send_frame_width);
762   }
763   if (video_sender_info.send_frame_height > 0) {
764     outbound_video->frame_height =
765         static_cast<uint32_t>(video_sender_info.send_frame_height);
766   }
767   if (video_sender_info.framerate_sent > 0) {
768     outbound_video->frames_per_second = video_sender_info.framerate_sent;
769   }
770   outbound_video->frames_sent = video_sender_info.frames_sent;
771   outbound_video->huge_frames_sent = video_sender_info.huge_frames_sent;
772   outbound_video->quality_limitation_reason =
773       QualityLimitationReasonToRTCQualityLimitationReason(
774           video_sender_info.quality_limitation_reason);
775   outbound_video->quality_limitation_durations =
776       QualityLimitationDurationToRTCQualityLimitationDuration(
777           video_sender_info.quality_limitation_durations_ms);
778   outbound_video->quality_limitation_resolution_changes =
779       video_sender_info.quality_limitation_resolution_changes;
780   // TODO(https://crbug.com/webrtc/10529): When info's `content_info` is
781   // optional, support the "unspecified" value.
782   if (video_sender_info.content_type == VideoContentType::SCREENSHARE)
783     outbound_video->content_type = RTCContentType::kScreenshare;
784   if (!video_sender_info.encoder_implementation_name.empty()) {
785     outbound_video->encoder_implementation =
786         video_sender_info.encoder_implementation_name;
787   }
788   if (video_sender_info.rid.has_value()) {
789     outbound_video->rid = *video_sender_info.rid;
790   }
791   if (video_sender_info.power_efficient_encoder.has_value()) {
792     outbound_video->power_efficient_encoder =
793         video_sender_info.power_efficient_encoder.value();
794   }
795 }
796 
797 std::unique_ptr<RTCRemoteInboundRtpStreamStats>
ProduceRemoteInboundRtpStreamStatsFromReportBlockData(const std::string & transport_id,const ReportBlockData & report_block_data,cricket::MediaType media_type,const std::map<std::string,RTCOutboundRTPStreamStats * > & outbound_rtps,const RTCStatsReport & report)798 ProduceRemoteInboundRtpStreamStatsFromReportBlockData(
799     const std::string& transport_id,
800     const ReportBlockData& report_block_data,
801     cricket::MediaType media_type,
802     const std::map<std::string, RTCOutboundRTPStreamStats*>& outbound_rtps,
803     const RTCStatsReport& report) {
804   const auto& report_block = report_block_data.report_block();
805   // RTCStats' timestamp generally refers to when the metric was sampled, but
806   // for "remote-[outbound/inbound]-rtp" it refers to the local time when the
807   // Report Block was received.
808   auto remote_inbound = std::make_unique<RTCRemoteInboundRtpStreamStats>(
809       RTCRemoteInboundRtpStreamStatsIdFromSourceSsrc(media_type,
810                                                      report_block.source_ssrc),
811       /*timestamp=*/report_block_data.report_block_timestamp_utc_us());
812   remote_inbound->ssrc = report_block.source_ssrc;
813   remote_inbound->kind =
814       media_type == cricket::MEDIA_TYPE_AUDIO ? "audio" : "video";
815   remote_inbound->packets_lost = report_block.packets_lost;
816   remote_inbound->fraction_lost =
817       static_cast<double>(report_block.fraction_lost) / (1 << 8);
818   if (report_block_data.num_rtts() > 0) {
819     remote_inbound->round_trip_time =
820         static_cast<double>(report_block_data.last_rtt_ms()) /
821         rtc::kNumMillisecsPerSec;
822   }
823   remote_inbound->total_round_trip_time =
824       static_cast<double>(report_block_data.sum_rtt_ms()) /
825       rtc::kNumMillisecsPerSec;
826   remote_inbound->round_trip_time_measurements =
827       report_block_data.num_rtts();
828 
829   std::string local_id = RTCOutboundRTPStreamStatsIDFromSSRC(
830       transport_id, media_type, report_block.source_ssrc);
831   // Look up local stat from `outbound_rtps` where the pointers are non-const.
832   auto local_id_it = outbound_rtps.find(local_id);
833   if (local_id_it != outbound_rtps.end()) {
834     remote_inbound->local_id = local_id;
835     auto& outbound_rtp = *local_id_it->second;
836     outbound_rtp.remote_id = remote_inbound->id();
837     // The RTP/RTCP transport is obtained from the
838     // RTCOutboundRtpStreamStats's transport.
839     const auto* transport_from_id = report.Get(transport_id);
840     if (transport_from_id) {
841       const auto& transport = transport_from_id->cast_to<RTCTransportStats>();
842       // If RTP and RTCP are not multiplexed, there is a separate RTCP
843       // transport paired with the RTP transport, otherwise the same
844       // transport is used for RTCP and RTP.
845       remote_inbound->transport_id =
846           transport.rtcp_transport_stats_id.is_defined()
847               ? *transport.rtcp_transport_stats_id
848               : *outbound_rtp.transport_id;
849     }
850     // We're assuming the same codec is used on both ends. However if the
851     // codec is switched out on the fly we may have received a Report Block
852     // based on the previous codec and there is no way to tell which point in
853     // time the codec changed for the remote end.
854     const auto* codec_from_id = outbound_rtp.codec_id.is_defined()
855                                     ? report.Get(*outbound_rtp.codec_id)
856                                     : nullptr;
857     if (codec_from_id) {
858       remote_inbound->codec_id = *outbound_rtp.codec_id;
859       const auto& codec = codec_from_id->cast_to<RTCCodecStats>();
860       if (codec.clock_rate.is_defined()) {
861         // The Report Block jitter is expressed in RTP timestamp units
862         // (https://tools.ietf.org/html/rfc3550#section-6.4.1). To convert this
863         // to seconds we divide by the codec's clock rate.
864         remote_inbound->jitter =
865             static_cast<double>(report_block.jitter) / *codec.clock_rate;
866       }
867     }
868   }
869   return remote_inbound;
870 }
871 
ProduceCertificateStatsFromSSLCertificateStats(int64_t timestamp_us,const rtc::SSLCertificateStats & certificate_stats,RTCStatsReport * report)872 void ProduceCertificateStatsFromSSLCertificateStats(
873     int64_t timestamp_us,
874     const rtc::SSLCertificateStats& certificate_stats,
875     RTCStatsReport* report) {
876   RTCCertificateStats* prev_certificate_stats = nullptr;
877   for (const rtc::SSLCertificateStats* s = &certificate_stats; s;
878        s = s->issuer.get()) {
879     std::string certificate_stats_id =
880         RTCCertificateIDFromFingerprint(s->fingerprint);
881     // It is possible for the same certificate to show up multiple times, e.g.
882     // if local and remote side use the same certificate in a loopback call.
883     // If the report already contains stats for this certificate, skip it.
884     if (report->Get(certificate_stats_id)) {
885       RTC_DCHECK_EQ(s, &certificate_stats);
886       break;
887     }
888     RTCCertificateStats* certificate_stats =
889         new RTCCertificateStats(certificate_stats_id, timestamp_us);
890     certificate_stats->fingerprint = s->fingerprint;
891     certificate_stats->fingerprint_algorithm = s->fingerprint_algorithm;
892     certificate_stats->base64_certificate = s->base64_certificate;
893     if (prev_certificate_stats)
894       prev_certificate_stats->issuer_certificate_id = certificate_stats->id();
895     report->AddStats(std::unique_ptr<RTCCertificateStats>(certificate_stats));
896     prev_certificate_stats = certificate_stats;
897   }
898 }
899 
ProduceIceCandidateStats(int64_t timestamp_us,const cricket::Candidate & candidate,bool is_local,const std::string & transport_id,RTCStatsReport * report)900 const std::string& ProduceIceCandidateStats(int64_t timestamp_us,
901                                             const cricket::Candidate& candidate,
902                                             bool is_local,
903                                             const std::string& transport_id,
904                                             RTCStatsReport* report) {
905   const std::string& id = "I" + candidate.id();
906   const RTCStats* stats = report->Get(id);
907   if (!stats) {
908     std::unique_ptr<RTCIceCandidateStats> candidate_stats;
909     if (is_local)
910       candidate_stats =
911           std::make_unique<RTCLocalIceCandidateStats>(id, timestamp_us);
912     else
913       candidate_stats =
914           std::make_unique<RTCRemoteIceCandidateStats>(id, timestamp_us);
915     candidate_stats->transport_id = transport_id;
916     if (is_local) {
917       candidate_stats->network_type =
918           NetworkTypeToStatsType(candidate.network_type());
919       const std::string& candidate_type = candidate.type();
920       const std::string& relay_protocol = candidate.relay_protocol();
921       const std::string& url = candidate.url();
922       if (candidate_type == cricket::RELAY_PORT_TYPE ||
923           (candidate_type == cricket::PRFLX_PORT_TYPE &&
924            !relay_protocol.empty())) {
925         RTC_DCHECK(relay_protocol.compare("udp") == 0 ||
926                    relay_protocol.compare("tcp") == 0 ||
927                    relay_protocol.compare("tls") == 0);
928         candidate_stats->relay_protocol = relay_protocol;
929         if (!url.empty()) {
930           candidate_stats->url = url;
931         }
932       } else if (candidate_type == cricket::STUN_PORT_TYPE) {
933         if (!url.empty()) {
934           candidate_stats->url = url;
935         }
936       }
937       if (candidate.network_type() == rtc::ADAPTER_TYPE_VPN) {
938         candidate_stats->vpn = true;
939         candidate_stats->network_adapter_type =
940             std::string(NetworkTypeToStatsNetworkAdapterType(
941                 candidate.underlying_type_for_vpn()));
942       } else {
943         candidate_stats->vpn = false;
944         candidate_stats->network_adapter_type = std::string(
945             NetworkTypeToStatsNetworkAdapterType(candidate.network_type()));
946       }
947     } else {
948       // We don't expect to know the adapter type of remote candidates.
949       RTC_DCHECK_EQ(rtc::ADAPTER_TYPE_UNKNOWN, candidate.network_type());
950       RTC_DCHECK_EQ(0, candidate.relay_protocol().compare(""));
951       RTC_DCHECK_EQ(rtc::ADAPTER_TYPE_UNKNOWN,
952                     candidate.underlying_type_for_vpn());
953     }
954     candidate_stats->ip = candidate.address().ipaddr().ToString();
955     candidate_stats->address = candidate.address().ipaddr().ToString();
956     candidate_stats->port = static_cast<int32_t>(candidate.address().port());
957     candidate_stats->protocol = candidate.protocol();
958     candidate_stats->candidate_type =
959         CandidateTypeToRTCIceCandidateType(candidate.type());
960     candidate_stats->priority = static_cast<int32_t>(candidate.priority());
961     candidate_stats->foundation = candidate.foundation();
962     auto related_address = candidate.related_address();
963     if (related_address.port() != 0) {
964       candidate_stats->related_address = related_address.ipaddr().ToString();
965       candidate_stats->related_port =
966           static_cast<int32_t>(related_address.port());
967     }
968     candidate_stats->username_fragment = candidate.username();
969     if (candidate.protocol() == "tcp") {
970       candidate_stats->tcp_type = candidate.tcptype();
971     }
972 
973     stats = candidate_stats.get();
974     report->AddStats(std::move(candidate_stats));
975   }
976   RTC_DCHECK_EQ(stats->type(), is_local ? RTCLocalIceCandidateStats::kType
977                                         : RTCRemoteIceCandidateStats::kType);
978   return stats->id();
979 }
980 
981 template <typename StatsType>
SetAudioProcessingStats(StatsType * stats,const AudioProcessingStats & apm_stats)982 void SetAudioProcessingStats(StatsType* stats,
983                              const AudioProcessingStats& apm_stats) {
984   if (apm_stats.echo_return_loss.has_value()) {
985     stats->echo_return_loss = *apm_stats.echo_return_loss;
986   }
987   if (apm_stats.echo_return_loss_enhancement.has_value()) {
988     stats->echo_return_loss_enhancement =
989         *apm_stats.echo_return_loss_enhancement;
990   }
991 }
992 
993 std::unique_ptr<DEPRECATED_RTCMediaStreamTrackStats>
ProduceMediaStreamTrackStatsFromVoiceSenderInfo(int64_t timestamp_us,AudioTrackInterface & audio_track,const cricket::VoiceSenderInfo & voice_sender_info,int attachment_id)994 ProduceMediaStreamTrackStatsFromVoiceSenderInfo(
995     int64_t timestamp_us,
996     AudioTrackInterface& audio_track,
997     const cricket::VoiceSenderInfo& voice_sender_info,
998     int attachment_id) {
999   std::unique_ptr<DEPRECATED_RTCMediaStreamTrackStats> audio_track_stats(
1000       std::make_unique<DEPRECATED_RTCMediaStreamTrackStats>(
1001           DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
1002               kDirectionOutbound, attachment_id),
1003           timestamp_us, RTCMediaStreamTrackKind::kAudio));
1004   SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
1005       audio_track, audio_track_stats.get());
1006   audio_track_stats->media_source_id =
1007       RTCMediaSourceStatsIDFromKindAndAttachment(cricket::MEDIA_TYPE_AUDIO,
1008                                                  attachment_id);
1009   audio_track_stats->remote_source = false;
1010   audio_track_stats->detached = false;
1011   // Audio processor may be attached to either the track or the send
1012   // stream, so look in both places.
1013   SetAudioProcessingStats(audio_track_stats.get(),
1014                           voice_sender_info.apm_statistics);
1015   auto audio_processor(audio_track.GetAudioProcessor());
1016   if (audio_processor.get()) {
1017     // The `has_remote_tracks` argument is obsolete; makes no difference if it's
1018     // set to true or false.
1019     AudioProcessorInterface::AudioProcessorStatistics ap_stats =
1020         audio_processor->GetStats(/*has_remote_tracks=*/false);
1021     SetAudioProcessingStats(audio_track_stats.get(), ap_stats.apm_statistics);
1022   }
1023   return audio_track_stats;
1024 }
1025 
1026 std::unique_ptr<DEPRECATED_RTCMediaStreamTrackStats>
ProduceMediaStreamTrackStatsFromVoiceReceiverInfo(int64_t timestamp_us,const AudioTrackInterface & audio_track,const cricket::VoiceReceiverInfo & voice_receiver_info,int attachment_id)1027 ProduceMediaStreamTrackStatsFromVoiceReceiverInfo(
1028     int64_t timestamp_us,
1029     const AudioTrackInterface& audio_track,
1030     const cricket::VoiceReceiverInfo& voice_receiver_info,
1031     int attachment_id) {
1032   // Since receiver tracks can't be reattached, we use the SSRC as
1033   // an attachment identifier.
1034   std::unique_ptr<DEPRECATED_RTCMediaStreamTrackStats> audio_track_stats(
1035       std::make_unique<DEPRECATED_RTCMediaStreamTrackStats>(
1036           DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
1037               kDirectionInbound, attachment_id),
1038           timestamp_us, RTCMediaStreamTrackKind::kAudio));
1039   SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
1040       audio_track, audio_track_stats.get());
1041   audio_track_stats->remote_source = true;
1042   audio_track_stats->detached = false;
1043   if (voice_receiver_info.audio_level >= 0) {
1044     audio_track_stats->audio_level =
1045         DoubleAudioLevelFromIntAudioLevel(voice_receiver_info.audio_level);
1046   }
1047   audio_track_stats->jitter_buffer_delay =
1048       voice_receiver_info.jitter_buffer_delay_seconds;
1049   audio_track_stats->jitter_buffer_emitted_count =
1050       voice_receiver_info.jitter_buffer_emitted_count;
1051   audio_track_stats->inserted_samples_for_deceleration =
1052       voice_receiver_info.inserted_samples_for_deceleration;
1053   audio_track_stats->removed_samples_for_acceleration =
1054       voice_receiver_info.removed_samples_for_acceleration;
1055   audio_track_stats->total_audio_energy =
1056       voice_receiver_info.total_output_energy;
1057   audio_track_stats->total_samples_received =
1058       voice_receiver_info.total_samples_received;
1059   audio_track_stats->total_samples_duration =
1060       voice_receiver_info.total_output_duration;
1061   audio_track_stats->concealed_samples = voice_receiver_info.concealed_samples;
1062   audio_track_stats->silent_concealed_samples =
1063       voice_receiver_info.silent_concealed_samples;
1064   audio_track_stats->concealment_events =
1065       voice_receiver_info.concealment_events;
1066 
1067   return audio_track_stats;
1068 }
1069 
1070 std::unique_ptr<DEPRECATED_RTCMediaStreamTrackStats>
ProduceMediaStreamTrackStatsFromVideoSenderInfo(int64_t timestamp_us,const VideoTrackInterface & video_track,const cricket::VideoSenderInfo & video_sender_info,int attachment_id)1071 ProduceMediaStreamTrackStatsFromVideoSenderInfo(
1072     int64_t timestamp_us,
1073     const VideoTrackInterface& video_track,
1074     const cricket::VideoSenderInfo& video_sender_info,
1075     int attachment_id) {
1076   std::unique_ptr<DEPRECATED_RTCMediaStreamTrackStats> video_track_stats(
1077       std::make_unique<DEPRECATED_RTCMediaStreamTrackStats>(
1078           DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
1079               kDirectionOutbound, attachment_id),
1080           timestamp_us, RTCMediaStreamTrackKind::kVideo));
1081   SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
1082       video_track, video_track_stats.get());
1083   video_track_stats->media_source_id =
1084       RTCMediaSourceStatsIDFromKindAndAttachment(cricket::MEDIA_TYPE_VIDEO,
1085                                                  attachment_id);
1086   video_track_stats->remote_source = false;
1087   video_track_stats->detached = false;
1088   video_track_stats->frame_width =
1089       static_cast<uint32_t>(video_sender_info.send_frame_width);
1090   video_track_stats->frame_height =
1091       static_cast<uint32_t>(video_sender_info.send_frame_height);
1092   // TODO(hbos): Will reduce this by frames dropped due to congestion control
1093   // when available. https://crbug.com/659137
1094   video_track_stats->frames_sent = video_sender_info.frames_encoded;
1095   video_track_stats->huge_frames_sent = video_sender_info.huge_frames_sent;
1096   return video_track_stats;
1097 }
1098 
1099 std::unique_ptr<DEPRECATED_RTCMediaStreamTrackStats>
ProduceMediaStreamTrackStatsFromVideoReceiverInfo(int64_t timestamp_us,const VideoTrackInterface & video_track,const cricket::VideoReceiverInfo & video_receiver_info,int attachment_id)1100 ProduceMediaStreamTrackStatsFromVideoReceiverInfo(
1101     int64_t timestamp_us,
1102     const VideoTrackInterface& video_track,
1103     const cricket::VideoReceiverInfo& video_receiver_info,
1104     int attachment_id) {
1105   std::unique_ptr<DEPRECATED_RTCMediaStreamTrackStats> video_track_stats(
1106       std::make_unique<DEPRECATED_RTCMediaStreamTrackStats>(
1107           DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
1108               kDirectionInbound, attachment_id),
1109           timestamp_us, RTCMediaStreamTrackKind::kVideo));
1110   SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
1111       video_track, video_track_stats.get());
1112   video_track_stats->remote_source = true;
1113   video_track_stats->detached = false;
1114   if (video_receiver_info.frame_width > 0 &&
1115       video_receiver_info.frame_height > 0) {
1116     video_track_stats->frame_width =
1117         static_cast<uint32_t>(video_receiver_info.frame_width);
1118     video_track_stats->frame_height =
1119         static_cast<uint32_t>(video_receiver_info.frame_height);
1120   }
1121   video_track_stats->jitter_buffer_delay =
1122       video_receiver_info.jitter_buffer_delay_seconds;
1123   video_track_stats->jitter_buffer_emitted_count =
1124       video_receiver_info.jitter_buffer_emitted_count;
1125   video_track_stats->frames_received = video_receiver_info.frames_received;
1126   // TODO(hbos): When we support receiving simulcast, this should be the total
1127   // number of frames correctly decoded, independent of which SSRC it was
1128   // received from. Since we don't support that, this is correct and is the same
1129   // value as "RTCInboundRTPStreamStats.framesDecoded". https://crbug.com/659137
1130   video_track_stats->frames_decoded = video_receiver_info.frames_decoded;
1131   video_track_stats->frames_dropped = video_receiver_info.frames_dropped;
1132 
1133   return video_track_stats;
1134 }
1135 
ProduceSenderMediaTrackStats(int64_t timestamp_us,const TrackMediaInfoMap & track_media_info_map,std::vector<rtc::scoped_refptr<RtpSenderInternal>> senders,RTCStatsReport * report)1136 void ProduceSenderMediaTrackStats(
1137     int64_t timestamp_us,
1138     const TrackMediaInfoMap& track_media_info_map,
1139     std::vector<rtc::scoped_refptr<RtpSenderInternal>> senders,
1140     RTCStatsReport* report) {
1141   // This function iterates over the senders to generate outgoing track stats.
1142 
1143   // TODO(https://crbug.com/webrtc/14175): Stop collecting "track" stats,
1144   // they're deprecated.
1145   for (const auto& sender : senders) {
1146     if (sender->media_type() == cricket::MEDIA_TYPE_AUDIO) {
1147       AudioTrackInterface* track =
1148           static_cast<AudioTrackInterface*>(sender->track().get());
1149       if (!track)
1150         continue;
1151       cricket::VoiceSenderInfo null_sender_info;
1152       const cricket::VoiceSenderInfo* voice_sender_info = &null_sender_info;
1153       // TODO(hta): Checking on ssrc is not proper. There should be a way
1154       // to see from a sender whether it's connected or not.
1155       // Related to https://crbug.com/8694 (using ssrc 0 to indicate "none")
1156       if (sender->ssrc() != 0) {
1157         // When pc.close is called, sender info is discarded, so
1158         // we generate zeroes instead. Bug: It should be retained.
1159         // https://crbug.com/807174
1160         const cricket::VoiceSenderInfo* sender_info =
1161             track_media_info_map.GetVoiceSenderInfoBySsrc(sender->ssrc());
1162         if (sender_info) {
1163           voice_sender_info = sender_info;
1164         } else {
1165           RTC_DLOG(LS_INFO)
1166               << "RTCStatsCollector: No voice sender info for sender with ssrc "
1167               << sender->ssrc();
1168         }
1169       }
1170       std::unique_ptr<DEPRECATED_RTCMediaStreamTrackStats> audio_track_stats =
1171           ProduceMediaStreamTrackStatsFromVoiceSenderInfo(
1172               timestamp_us, *track, *voice_sender_info, sender->AttachmentId());
1173       report->AddStats(std::move(audio_track_stats));
1174     } else if (sender->media_type() == cricket::MEDIA_TYPE_VIDEO) {
1175       VideoTrackInterface* track =
1176           static_cast<VideoTrackInterface*>(sender->track().get());
1177       if (!track)
1178         continue;
1179       cricket::VideoSenderInfo null_sender_info;
1180       const cricket::VideoSenderInfo* video_sender_info = &null_sender_info;
1181       // TODO(hta): Check on state not ssrc when state is available
1182       // Related to https://bugs.webrtc.org/8694 (using ssrc 0 to indicate
1183       // "none")
1184       if (sender->ssrc() != 0) {
1185         // When pc.close is called, sender info is discarded, so
1186         // we generate zeroes instead. Bug: It should be retained.
1187         // https://crbug.com/807174
1188         const cricket::VideoSenderInfo* sender_info =
1189             track_media_info_map.GetVideoSenderInfoBySsrc(sender->ssrc());
1190         if (sender_info) {
1191           video_sender_info = sender_info;
1192         } else {
1193           RTC_DLOG(LS_INFO)
1194               << "No video sender info for sender with ssrc " << sender->ssrc();
1195         }
1196       }
1197       std::unique_ptr<DEPRECATED_RTCMediaStreamTrackStats> video_track_stats =
1198           ProduceMediaStreamTrackStatsFromVideoSenderInfo(
1199               timestamp_us, *track, *video_sender_info, sender->AttachmentId());
1200       report->AddStats(std::move(video_track_stats));
1201     } else {
1202       RTC_DCHECK_NOTREACHED();
1203     }
1204   }
1205 }
1206 
ProduceReceiverMediaTrackStats(int64_t timestamp_us,const TrackMediaInfoMap & track_media_info_map,std::vector<rtc::scoped_refptr<RtpReceiverInternal>> receivers,RTCStatsReport * report)1207 void ProduceReceiverMediaTrackStats(
1208     int64_t timestamp_us,
1209     const TrackMediaInfoMap& track_media_info_map,
1210     std::vector<rtc::scoped_refptr<RtpReceiverInternal>> receivers,
1211     RTCStatsReport* report) {
1212   // This function iterates over the receivers to find the remote tracks.
1213   for (const auto& receiver : receivers) {
1214     if (receiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
1215       AudioTrackInterface* track =
1216           static_cast<AudioTrackInterface*>(receiver->track().get());
1217       const cricket::VoiceReceiverInfo* voice_receiver_info =
1218           track_media_info_map.GetVoiceReceiverInfo(*track);
1219       if (!voice_receiver_info) {
1220         continue;
1221       }
1222       std::unique_ptr<DEPRECATED_RTCMediaStreamTrackStats> audio_track_stats =
1223           ProduceMediaStreamTrackStatsFromVoiceReceiverInfo(
1224               timestamp_us, *track, *voice_receiver_info,
1225               receiver->AttachmentId());
1226       report->AddStats(std::move(audio_track_stats));
1227     } else if (receiver->media_type() == cricket::MEDIA_TYPE_VIDEO) {
1228       VideoTrackInterface* track =
1229           static_cast<VideoTrackInterface*>(receiver->track().get());
1230       const cricket::VideoReceiverInfo* video_receiver_info =
1231           track_media_info_map.GetVideoReceiverInfo(*track);
1232       if (!video_receiver_info) {
1233         continue;
1234       }
1235       std::unique_ptr<DEPRECATED_RTCMediaStreamTrackStats> video_track_stats =
1236           ProduceMediaStreamTrackStatsFromVideoReceiverInfo(
1237               timestamp_us, *track, *video_receiver_info,
1238               receiver->AttachmentId());
1239       report->AddStats(std::move(video_track_stats));
1240     } else {
1241       RTC_DCHECK_NOTREACHED();
1242     }
1243   }
1244 }
1245 
CreateReportFilteredBySelector(bool filter_by_sender_selector,rtc::scoped_refptr<const RTCStatsReport> report,rtc::scoped_refptr<RtpSenderInternal> sender_selector,rtc::scoped_refptr<RtpReceiverInternal> receiver_selector)1246 rtc::scoped_refptr<RTCStatsReport> CreateReportFilteredBySelector(
1247     bool filter_by_sender_selector,
1248     rtc::scoped_refptr<const RTCStatsReport> report,
1249     rtc::scoped_refptr<RtpSenderInternal> sender_selector,
1250     rtc::scoped_refptr<RtpReceiverInternal> receiver_selector) {
1251   std::vector<std::string> rtpstream_ids;
1252   if (filter_by_sender_selector) {
1253     // Filter mode: RTCStatsCollector::RequestInfo::kSenderSelector
1254     if (sender_selector) {
1255       // Find outbound-rtp(s) of the sender, i.e. the outbound-rtp(s) that
1256       // reference the sender stats.
1257       // Because we do not implement sender stats, we look at outbound-rtp(s)
1258       // that reference the track attachment stats for the sender instead.
1259       std::string track_id =
1260           DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
1261               kDirectionOutbound, sender_selector->AttachmentId());
1262       for (const auto& stats : *report) {
1263         if (stats.type() != RTCOutboundRTPStreamStats::kType)
1264           continue;
1265         const auto& outbound_rtp = stats.cast_to<RTCOutboundRTPStreamStats>();
1266         if (outbound_rtp.track_id.is_defined() &&
1267             *outbound_rtp.track_id == track_id) {
1268           rtpstream_ids.push_back(outbound_rtp.id());
1269         }
1270       }
1271     }
1272   } else {
1273     // Filter mode: RTCStatsCollector::RequestInfo::kReceiverSelector
1274     if (receiver_selector) {
1275       // Find inbound-rtp(s) of the receiver, i.e. the inbound-rtp(s) that
1276       // reference the receiver stats.
1277       // Because we do not implement receiver stats, we look at inbound-rtp(s)
1278       // that reference the track attachment stats for the receiver instead.
1279       std::string track_id =
1280           DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
1281               kDirectionInbound, receiver_selector->AttachmentId());
1282       for (const auto& stats : *report) {
1283         if (stats.type() != RTCInboundRTPStreamStats::kType)
1284           continue;
1285         const auto& inbound_rtp = stats.cast_to<RTCInboundRTPStreamStats>();
1286         if (inbound_rtp.track_id.is_defined() &&
1287             *inbound_rtp.track_id == track_id) {
1288           rtpstream_ids.push_back(inbound_rtp.id());
1289         }
1290       }
1291     }
1292   }
1293   if (rtpstream_ids.empty())
1294     return RTCStatsReport::Create(report->timestamp());
1295   return TakeReferencedStats(report->Copy(), rtpstream_ids);
1296 }
1297 
1298 }  // namespace
1299 
1300 RTCStatsCollector::CertificateStatsPair
Copy() const1301 RTCStatsCollector::CertificateStatsPair::Copy() const {
1302   CertificateStatsPair copy;
1303   copy.local = local ? local->Copy() : nullptr;
1304   copy.remote = remote ? remote->Copy() : nullptr;
1305   return copy;
1306 }
1307 
RequestInfo(rtc::scoped_refptr<RTCStatsCollectorCallback> callback)1308 RTCStatsCollector::RequestInfo::RequestInfo(
1309     rtc::scoped_refptr<RTCStatsCollectorCallback> callback)
1310     : RequestInfo(FilterMode::kAll, std::move(callback), nullptr, nullptr) {}
1311 
RequestInfo(rtc::scoped_refptr<RtpSenderInternal> selector,rtc::scoped_refptr<RTCStatsCollectorCallback> callback)1312 RTCStatsCollector::RequestInfo::RequestInfo(
1313     rtc::scoped_refptr<RtpSenderInternal> selector,
1314     rtc::scoped_refptr<RTCStatsCollectorCallback> callback)
1315     : RequestInfo(FilterMode::kSenderSelector,
1316                   std::move(callback),
1317                   std::move(selector),
1318                   nullptr) {}
1319 
RequestInfo(rtc::scoped_refptr<RtpReceiverInternal> selector,rtc::scoped_refptr<RTCStatsCollectorCallback> callback)1320 RTCStatsCollector::RequestInfo::RequestInfo(
1321     rtc::scoped_refptr<RtpReceiverInternal> selector,
1322     rtc::scoped_refptr<RTCStatsCollectorCallback> callback)
1323     : RequestInfo(FilterMode::kReceiverSelector,
1324                   std::move(callback),
1325                   nullptr,
1326                   std::move(selector)) {}
1327 
RequestInfo(RTCStatsCollector::RequestInfo::FilterMode filter_mode,rtc::scoped_refptr<RTCStatsCollectorCallback> callback,rtc::scoped_refptr<RtpSenderInternal> sender_selector,rtc::scoped_refptr<RtpReceiverInternal> receiver_selector)1328 RTCStatsCollector::RequestInfo::RequestInfo(
1329     RTCStatsCollector::RequestInfo::FilterMode filter_mode,
1330     rtc::scoped_refptr<RTCStatsCollectorCallback> callback,
1331     rtc::scoped_refptr<RtpSenderInternal> sender_selector,
1332     rtc::scoped_refptr<RtpReceiverInternal> receiver_selector)
1333     : filter_mode_(filter_mode),
1334       callback_(std::move(callback)),
1335       sender_selector_(std::move(sender_selector)),
1336       receiver_selector_(std::move(receiver_selector)) {
1337   RTC_DCHECK(callback_);
1338   RTC_DCHECK(!sender_selector_ || !receiver_selector_);
1339 }
1340 
Create(PeerConnectionInternal * pc,int64_t cache_lifetime_us)1341 rtc::scoped_refptr<RTCStatsCollector> RTCStatsCollector::Create(
1342     PeerConnectionInternal* pc,
1343     int64_t cache_lifetime_us) {
1344   return rtc::make_ref_counted<RTCStatsCollector>(pc, cache_lifetime_us);
1345 }
1346 
RTCStatsCollector(PeerConnectionInternal * pc,int64_t cache_lifetime_us)1347 RTCStatsCollector::RTCStatsCollector(PeerConnectionInternal* pc,
1348                                      int64_t cache_lifetime_us)
1349     : pc_(pc),
1350       signaling_thread_(pc->signaling_thread()),
1351       worker_thread_(pc->worker_thread()),
1352       network_thread_(pc->network_thread()),
1353       num_pending_partial_reports_(0),
1354       partial_report_timestamp_us_(0),
1355       network_report_event_(true /* manual_reset */,
1356                             true /* initially_signaled */),
1357       cache_timestamp_us_(0),
1358       cache_lifetime_us_(cache_lifetime_us) {
1359   RTC_DCHECK(pc_);
1360   RTC_DCHECK(signaling_thread_);
1361   RTC_DCHECK(worker_thread_);
1362   RTC_DCHECK(network_thread_);
1363   RTC_DCHECK_GE(cache_lifetime_us_, 0);
1364   pc_->SignalSctpDataChannelCreated().connect(
1365       this, &RTCStatsCollector::OnSctpDataChannelCreated);
1366 }
1367 
~RTCStatsCollector()1368 RTCStatsCollector::~RTCStatsCollector() {
1369   RTC_DCHECK_EQ(num_pending_partial_reports_, 0);
1370 }
1371 
GetStatsReport(rtc::scoped_refptr<RTCStatsCollectorCallback> callback)1372 void RTCStatsCollector::GetStatsReport(
1373     rtc::scoped_refptr<RTCStatsCollectorCallback> callback) {
1374   GetStatsReportInternal(RequestInfo(std::move(callback)));
1375 }
1376 
GetStatsReport(rtc::scoped_refptr<RtpSenderInternal> selector,rtc::scoped_refptr<RTCStatsCollectorCallback> callback)1377 void RTCStatsCollector::GetStatsReport(
1378     rtc::scoped_refptr<RtpSenderInternal> selector,
1379     rtc::scoped_refptr<RTCStatsCollectorCallback> callback) {
1380   GetStatsReportInternal(RequestInfo(std::move(selector), std::move(callback)));
1381 }
1382 
GetStatsReport(rtc::scoped_refptr<RtpReceiverInternal> selector,rtc::scoped_refptr<RTCStatsCollectorCallback> callback)1383 void RTCStatsCollector::GetStatsReport(
1384     rtc::scoped_refptr<RtpReceiverInternal> selector,
1385     rtc::scoped_refptr<RTCStatsCollectorCallback> callback) {
1386   GetStatsReportInternal(RequestInfo(std::move(selector), std::move(callback)));
1387 }
1388 
GetStatsReportInternal(RTCStatsCollector::RequestInfo request)1389 void RTCStatsCollector::GetStatsReportInternal(
1390     RTCStatsCollector::RequestInfo request) {
1391   RTC_DCHECK_RUN_ON(signaling_thread_);
1392   requests_.push_back(std::move(request));
1393 
1394   // "Now" using a monotonically increasing timer.
1395   int64_t cache_now_us = rtc::TimeMicros();
1396   if (cached_report_ &&
1397       cache_now_us - cache_timestamp_us_ <= cache_lifetime_us_) {
1398     // We have a fresh cached report to deliver. Deliver asynchronously, since
1399     // the caller may not be expecting a synchronous callback, and it avoids
1400     // reentrancy problems.
1401     signaling_thread_->PostTask(
1402         absl::bind_front(&RTCStatsCollector::DeliverCachedReport,
1403                          rtc::scoped_refptr<RTCStatsCollector>(this),
1404                          cached_report_, std::move(requests_)));
1405   } else if (!num_pending_partial_reports_) {
1406     // Only start gathering stats if we're not already gathering stats. In the
1407     // case of already gathering stats, `callback_` will be invoked when there
1408     // are no more pending partial reports.
1409 
1410     // "Now" using a system clock, relative to the UNIX epoch (Jan 1, 1970,
1411     // UTC), in microseconds. The system clock could be modified and is not
1412     // necessarily monotonically increasing.
1413     int64_t timestamp_us = rtc::TimeUTCMicros();
1414 
1415     num_pending_partial_reports_ = 2;
1416     partial_report_timestamp_us_ = cache_now_us;
1417 
1418     // Prepare `transceiver_stats_infos_` and `call_stats_` for use in
1419     // `ProducePartialResultsOnNetworkThread` and
1420     // `ProducePartialResultsOnSignalingThread`.
1421     PrepareTransceiverStatsInfosAndCallStats_s_w_n();
1422     // Don't touch `network_report_` on the signaling thread until
1423     // ProducePartialResultsOnNetworkThread() has signaled the
1424     // `network_report_event_`.
1425     network_report_event_.Reset();
1426     rtc::scoped_refptr<RTCStatsCollector> collector(this);
1427     network_thread_->PostTask(
1428         [collector, sctp_transport_name = pc_->sctp_transport_name(),
1429          timestamp_us]() mutable {
1430           collector->ProducePartialResultsOnNetworkThread(
1431               timestamp_us, std::move(sctp_transport_name));
1432         });
1433     ProducePartialResultsOnSignalingThread(timestamp_us);
1434   }
1435 }
1436 
ClearCachedStatsReport()1437 void RTCStatsCollector::ClearCachedStatsReport() {
1438   RTC_DCHECK_RUN_ON(signaling_thread_);
1439   cached_report_ = nullptr;
1440   MutexLock lock(&cached_certificates_mutex_);
1441   cached_certificates_by_transport_.clear();
1442 }
1443 
WaitForPendingRequest()1444 void RTCStatsCollector::WaitForPendingRequest() {
1445   RTC_DCHECK_RUN_ON(signaling_thread_);
1446   // If a request is pending, blocks until the `network_report_event_` is
1447   // signaled and then delivers the result. Otherwise this is a NO-OP.
1448   MergeNetworkReport_s();
1449 }
1450 
ProducePartialResultsOnSignalingThread(int64_t timestamp_us)1451 void RTCStatsCollector::ProducePartialResultsOnSignalingThread(
1452     int64_t timestamp_us) {
1453   RTC_DCHECK_RUN_ON(signaling_thread_);
1454   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1455 
1456   partial_report_ = RTCStatsReport::Create(Timestamp::Micros(timestamp_us));
1457 
1458   ProducePartialResultsOnSignalingThreadImpl(timestamp_us,
1459                                              partial_report_.get());
1460 
1461   // ProducePartialResultsOnSignalingThread() is running synchronously on the
1462   // signaling thread, so it is always the first partial result delivered on the
1463   // signaling thread. The request is not complete until MergeNetworkReport_s()
1464   // happens; we don't have to do anything here.
1465   RTC_DCHECK_GT(num_pending_partial_reports_, 1);
1466   --num_pending_partial_reports_;
1467 }
1468 
ProducePartialResultsOnSignalingThreadImpl(int64_t timestamp_us,RTCStatsReport * partial_report)1469 void RTCStatsCollector::ProducePartialResultsOnSignalingThreadImpl(
1470     int64_t timestamp_us,
1471     RTCStatsReport* partial_report) {
1472   RTC_DCHECK_RUN_ON(signaling_thread_);
1473   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1474 
1475   ProduceDataChannelStats_s(timestamp_us, partial_report);
1476   ProduceMediaStreamStats_s(timestamp_us, partial_report);
1477   ProduceMediaStreamTrackStats_s(timestamp_us, partial_report);
1478   ProduceMediaSourceStats_s(timestamp_us, partial_report);
1479   ProducePeerConnectionStats_s(timestamp_us, partial_report);
1480 }
1481 
ProducePartialResultsOnNetworkThread(int64_t timestamp_us,absl::optional<std::string> sctp_transport_name)1482 void RTCStatsCollector::ProducePartialResultsOnNetworkThread(
1483     int64_t timestamp_us,
1484     absl::optional<std::string> sctp_transport_name) {
1485   TRACE_EVENT0("webrtc",
1486                "RTCStatsCollector::ProducePartialResultsOnNetworkThread");
1487   RTC_DCHECK_RUN_ON(network_thread_);
1488   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1489 
1490   // Touching `network_report_` on this thread is safe by this method because
1491   // `network_report_event_` is reset before this method is invoked.
1492   network_report_ = RTCStatsReport::Create(Timestamp::Micros(timestamp_us));
1493 
1494   std::set<std::string> transport_names;
1495   if (sctp_transport_name) {
1496     transport_names.emplace(std::move(*sctp_transport_name));
1497   }
1498 
1499   for (const auto& info : transceiver_stats_infos_) {
1500     if (info.transport_name)
1501       transport_names.insert(*info.transport_name);
1502   }
1503 
1504   std::map<std::string, cricket::TransportStats> transport_stats_by_name =
1505       pc_->GetTransportStatsByNames(transport_names);
1506   std::map<std::string, CertificateStatsPair> transport_cert_stats =
1507       PrepareTransportCertificateStats_n(transport_stats_by_name);
1508 
1509   ProducePartialResultsOnNetworkThreadImpl(
1510       timestamp_us, transport_stats_by_name, transport_cert_stats,
1511       network_report_.get());
1512 
1513   // Signal that it is now safe to touch `network_report_` on the signaling
1514   // thread, and post a task to merge it into the final results.
1515   network_report_event_.Set();
1516   rtc::scoped_refptr<RTCStatsCollector> collector(this);
1517   signaling_thread_->PostTask(
1518       [collector] { collector->MergeNetworkReport_s(); });
1519 }
1520 
ProducePartialResultsOnNetworkThreadImpl(int64_t timestamp_us,const std::map<std::string,cricket::TransportStats> & transport_stats_by_name,const std::map<std::string,CertificateStatsPair> & transport_cert_stats,RTCStatsReport * partial_report)1521 void RTCStatsCollector::ProducePartialResultsOnNetworkThreadImpl(
1522     int64_t timestamp_us,
1523     const std::map<std::string, cricket::TransportStats>&
1524         transport_stats_by_name,
1525     const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
1526     RTCStatsReport* partial_report) {
1527   RTC_DCHECK_RUN_ON(network_thread_);
1528   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1529 
1530   ProduceCertificateStats_n(timestamp_us, transport_cert_stats, partial_report);
1531   ProduceIceCandidateAndPairStats_n(timestamp_us, transport_stats_by_name,
1532                                     call_stats_, partial_report);
1533   ProduceTransportStats_n(timestamp_us, transport_stats_by_name,
1534                           transport_cert_stats, partial_report);
1535   ProduceRTPStreamStats_n(timestamp_us, transceiver_stats_infos_,
1536                           partial_report);
1537 }
1538 
MergeNetworkReport_s()1539 void RTCStatsCollector::MergeNetworkReport_s() {
1540   RTC_DCHECK_RUN_ON(signaling_thread_);
1541   // The `network_report_event_` must be signaled for it to be safe to touch
1542   // `network_report_`. This is normally not blocking, but if
1543   // WaitForPendingRequest() is called while a request is pending, we might have
1544   // to wait until the network thread is done touching `network_report_`.
1545   network_report_event_.Wait(rtc::Event::kForever);
1546   if (!network_report_) {
1547     // Normally, MergeNetworkReport_s() is executed because it is posted from
1548     // the network thread. But if WaitForPendingRequest() is called while a
1549     // request is pending, an early call to MergeNetworkReport_s() is made,
1550     // merging the report and setting `network_report_` to null. If so, when the
1551     // previously posted MergeNetworkReport_s() is later executed, the report is
1552     // already null and nothing needs to be done here.
1553     return;
1554   }
1555   RTC_DCHECK_GT(num_pending_partial_reports_, 0);
1556   RTC_DCHECK(partial_report_);
1557   partial_report_->TakeMembersFrom(network_report_);
1558   network_report_ = nullptr;
1559   --num_pending_partial_reports_;
1560   // `network_report_` is currently the only partial report collected
1561   // asynchronously, so `num_pending_partial_reports_` must now be 0 and we are
1562   // ready to deliver the result.
1563   RTC_DCHECK_EQ(num_pending_partial_reports_, 0);
1564   cache_timestamp_us_ = partial_report_timestamp_us_;
1565   cached_report_ = partial_report_;
1566   partial_report_ = nullptr;
1567   transceiver_stats_infos_.clear();
1568   // Trace WebRTC Stats when getStats is called on Javascript.
1569   // This allows access to WebRTC stats from trace logs. To enable them,
1570   // select the "webrtc_stats" category when recording traces.
1571   TRACE_EVENT_INSTANT1("webrtc_stats", "webrtc_stats", "report",
1572                        cached_report_->ToJson());
1573 
1574   // Deliver report and clear `requests_`.
1575   std::vector<RequestInfo> requests;
1576   requests.swap(requests_);
1577   DeliverCachedReport(cached_report_, std::move(requests));
1578 }
1579 
DeliverCachedReport(rtc::scoped_refptr<const RTCStatsReport> cached_report,std::vector<RTCStatsCollector::RequestInfo> requests)1580 void RTCStatsCollector::DeliverCachedReport(
1581     rtc::scoped_refptr<const RTCStatsReport> cached_report,
1582     std::vector<RTCStatsCollector::RequestInfo> requests) {
1583   RTC_DCHECK_RUN_ON(signaling_thread_);
1584   RTC_DCHECK(!requests.empty());
1585   RTC_DCHECK(cached_report);
1586 
1587   for (const RequestInfo& request : requests) {
1588     if (request.filter_mode() == RequestInfo::FilterMode::kAll) {
1589       request.callback()->OnStatsDelivered(cached_report);
1590     } else {
1591       bool filter_by_sender_selector;
1592       rtc::scoped_refptr<RtpSenderInternal> sender_selector;
1593       rtc::scoped_refptr<RtpReceiverInternal> receiver_selector;
1594       if (request.filter_mode() == RequestInfo::FilterMode::kSenderSelector) {
1595         filter_by_sender_selector = true;
1596         sender_selector = request.sender_selector();
1597       } else {
1598         RTC_DCHECK(request.filter_mode() ==
1599                    RequestInfo::FilterMode::kReceiverSelector);
1600         filter_by_sender_selector = false;
1601         receiver_selector = request.receiver_selector();
1602       }
1603       request.callback()->OnStatsDelivered(CreateReportFilteredBySelector(
1604           filter_by_sender_selector, cached_report, sender_selector,
1605           receiver_selector));
1606     }
1607   }
1608 }
1609 
ProduceCertificateStats_n(int64_t timestamp_us,const std::map<std::string,CertificateStatsPair> & transport_cert_stats,RTCStatsReport * report) const1610 void RTCStatsCollector::ProduceCertificateStats_n(
1611     int64_t timestamp_us,
1612     const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
1613     RTCStatsReport* report) const {
1614   RTC_DCHECK_RUN_ON(network_thread_);
1615   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1616 
1617   for (const auto& transport_cert_stats_pair : transport_cert_stats) {
1618     if (transport_cert_stats_pair.second.local) {
1619       ProduceCertificateStatsFromSSLCertificateStats(
1620           timestamp_us, *transport_cert_stats_pair.second.local.get(), report);
1621     }
1622     if (transport_cert_stats_pair.second.remote) {
1623       ProduceCertificateStatsFromSSLCertificateStats(
1624           timestamp_us, *transport_cert_stats_pair.second.remote.get(), report);
1625     }
1626   }
1627 }
1628 
ProduceDataChannelStats_s(int64_t timestamp_us,RTCStatsReport * report) const1629 void RTCStatsCollector::ProduceDataChannelStats_s(
1630     int64_t timestamp_us,
1631     RTCStatsReport* report) const {
1632   RTC_DCHECK_RUN_ON(signaling_thread_);
1633   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1634   std::vector<DataChannelStats> data_stats = pc_->GetDataChannelStats();
1635   for (const auto& stats : data_stats) {
1636     std::unique_ptr<RTCDataChannelStats> data_channel_stats(
1637         std::make_unique<RTCDataChannelStats>(
1638             "D" + rtc::ToString(stats.internal_id), timestamp_us));
1639     data_channel_stats->label = std::move(stats.label);
1640     data_channel_stats->protocol = std::move(stats.protocol);
1641     data_channel_stats->data_channel_identifier = stats.id;
1642     data_channel_stats->state = DataStateToRTCDataChannelState(stats.state);
1643     data_channel_stats->messages_sent = stats.messages_sent;
1644     data_channel_stats->bytes_sent = stats.bytes_sent;
1645     data_channel_stats->messages_received = stats.messages_received;
1646     data_channel_stats->bytes_received = stats.bytes_received;
1647     report->AddStats(std::move(data_channel_stats));
1648   }
1649 }
1650 
ProduceIceCandidateAndPairStats_n(int64_t timestamp_us,const std::map<std::string,cricket::TransportStats> & transport_stats_by_name,const Call::Stats & call_stats,RTCStatsReport * report) const1651 void RTCStatsCollector::ProduceIceCandidateAndPairStats_n(
1652     int64_t timestamp_us,
1653     const std::map<std::string, cricket::TransportStats>&
1654         transport_stats_by_name,
1655     const Call::Stats& call_stats,
1656     RTCStatsReport* report) const {
1657   RTC_DCHECK_RUN_ON(network_thread_);
1658   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1659 
1660   for (const auto& entry : transport_stats_by_name) {
1661     const std::string& transport_name = entry.first;
1662     const cricket::TransportStats& transport_stats = entry.second;
1663     for (const auto& channel_stats : transport_stats.channel_stats) {
1664       std::string transport_id = RTCTransportStatsIDFromTransportChannel(
1665           transport_name, channel_stats.component);
1666       for (const auto& info :
1667            channel_stats.ice_transport_stats.connection_infos) {
1668         std::unique_ptr<RTCIceCandidatePairStats> candidate_pair_stats(
1669             std::make_unique<RTCIceCandidatePairStats>(
1670                 RTCIceCandidatePairStatsIDFromConnectionInfo(info),
1671                 timestamp_us));
1672 
1673         candidate_pair_stats->transport_id = transport_id;
1674         // TODO(hbos): There could be other candidates that are not paired with
1675         // anything. We don't have a complete list. Local candidates come from
1676         // Port objects, and prflx candidates (both local and remote) are only
1677         // stored in candidate pairs. https://crbug.com/632723
1678         candidate_pair_stats->local_candidate_id = ProduceIceCandidateStats(
1679             timestamp_us, info.local_candidate, true, transport_id, report);
1680         candidate_pair_stats->remote_candidate_id = ProduceIceCandidateStats(
1681             timestamp_us, info.remote_candidate, false, transport_id, report);
1682         candidate_pair_stats->state =
1683             IceCandidatePairStateToRTCStatsIceCandidatePairState(info.state);
1684         candidate_pair_stats->priority = info.priority;
1685         candidate_pair_stats->nominated = info.nominated;
1686         // TODO(hbos): This writable is different than the spec. It goes to
1687         // false after a certain amount of time without a response passes.
1688         // https://crbug.com/633550
1689         candidate_pair_stats->writable = info.writable;
1690         // Note that sent_total_packets includes discarded packets but
1691         // sent_total_bytes does not.
1692         candidate_pair_stats->packets_sent = static_cast<uint64_t>(
1693             info.sent_total_packets - info.sent_discarded_packets);
1694         candidate_pair_stats->packets_discarded_on_send =
1695             static_cast<uint64_t>(info.sent_discarded_packets);
1696         candidate_pair_stats->packets_received =
1697             static_cast<uint64_t>(info.packets_received);
1698         candidate_pair_stats->bytes_sent =
1699             static_cast<uint64_t>(info.sent_total_bytes);
1700         candidate_pair_stats->bytes_discarded_on_send =
1701             static_cast<uint64_t>(info.sent_discarded_bytes);
1702         candidate_pair_stats->bytes_received =
1703             static_cast<uint64_t>(info.recv_total_bytes);
1704         candidate_pair_stats->total_round_trip_time =
1705             static_cast<double>(info.total_round_trip_time_ms) /
1706             rtc::kNumMillisecsPerSec;
1707         if (info.current_round_trip_time_ms.has_value()) {
1708           candidate_pair_stats->current_round_trip_time =
1709               static_cast<double>(*info.current_round_trip_time_ms) /
1710               rtc::kNumMillisecsPerSec;
1711         }
1712         if (info.best_connection) {
1713           // The bandwidth estimations we have are for the selected candidate
1714           // pair ("info.best_connection").
1715           RTC_DCHECK_GE(call_stats.send_bandwidth_bps, 0);
1716           RTC_DCHECK_GE(call_stats.recv_bandwidth_bps, 0);
1717           if (call_stats.send_bandwidth_bps > 0) {
1718             candidate_pair_stats->available_outgoing_bitrate =
1719                 static_cast<double>(call_stats.send_bandwidth_bps);
1720           }
1721           if (call_stats.recv_bandwidth_bps > 0) {
1722             candidate_pair_stats->available_incoming_bitrate =
1723                 static_cast<double>(call_stats.recv_bandwidth_bps);
1724           }
1725         }
1726         candidate_pair_stats->requests_received =
1727             static_cast<uint64_t>(info.recv_ping_requests);
1728         candidate_pair_stats->requests_sent =
1729             static_cast<uint64_t>(info.sent_ping_requests_total);
1730         candidate_pair_stats->responses_received =
1731             static_cast<uint64_t>(info.recv_ping_responses);
1732         candidate_pair_stats->responses_sent =
1733             static_cast<uint64_t>(info.sent_ping_responses);
1734         RTC_DCHECK_GE(info.sent_ping_requests_total,
1735                       info.sent_ping_requests_before_first_response);
1736         candidate_pair_stats->consent_requests_sent = static_cast<uint64_t>(
1737             info.sent_ping_requests_total -
1738             info.sent_ping_requests_before_first_response);
1739 
1740         if (info.last_data_received.has_value()) {
1741           candidate_pair_stats->last_packet_received_timestamp =
1742               static_cast<double>(info.last_data_received->ms());
1743         }
1744         if (info.last_data_sent) {
1745           candidate_pair_stats->last_packet_sent_timestamp =
1746               static_cast<double>(info.last_data_sent->ms());
1747         }
1748 
1749         report->AddStats(std::move(candidate_pair_stats));
1750       }
1751 
1752       // Produce local candidate stats. If a transport exists these will already
1753       // have been produced.
1754       for (const auto& candidate_stats :
1755            channel_stats.ice_transport_stats.candidate_stats_list) {
1756         const auto& candidate = candidate_stats.candidate();
1757         ProduceIceCandidateStats(timestamp_us, candidate, true, transport_id,
1758                                  report);
1759       }
1760     }
1761   }
1762 }
1763 
ProduceMediaStreamStats_s(int64_t timestamp_us,RTCStatsReport * report) const1764 void RTCStatsCollector::ProduceMediaStreamStats_s(
1765     int64_t timestamp_us,
1766     RTCStatsReport* report) const {
1767   RTC_DCHECK_RUN_ON(signaling_thread_);
1768   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1769 
1770   std::map<std::string, std::vector<std::string>> track_ids;
1771 
1772   for (const auto& stats : transceiver_stats_infos_) {
1773     for (const auto& sender : stats.transceiver->senders()) {
1774       std::string track_id =
1775           DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
1776               kDirectionOutbound, sender->internal()->AttachmentId());
1777       for (auto& stream_id : sender->stream_ids()) {
1778         track_ids[stream_id].push_back(track_id);
1779       }
1780     }
1781     for (const auto& receiver : stats.transceiver->receivers()) {
1782       std::string track_id =
1783           DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
1784               kDirectionInbound, receiver->internal()->AttachmentId());
1785       for (auto& stream : receiver->streams()) {
1786         track_ids[stream->id()].push_back(track_id);
1787       }
1788     }
1789   }
1790 
1791   // Build stats for each stream ID known.
1792   for (auto& it : track_ids) {
1793     std::unique_ptr<DEPRECATED_RTCMediaStreamStats> stream_stats(
1794         std::make_unique<DEPRECATED_RTCMediaStreamStats>(
1795             "DEPRECATED_S" + it.first, timestamp_us));
1796     stream_stats->stream_identifier = it.first;
1797     stream_stats->track_ids = it.second;
1798     report->AddStats(std::move(stream_stats));
1799   }
1800 }
1801 
ProduceMediaStreamTrackStats_s(int64_t timestamp_us,RTCStatsReport * report) const1802 void RTCStatsCollector::ProduceMediaStreamTrackStats_s(
1803     int64_t timestamp_us,
1804     RTCStatsReport* report) const {
1805   RTC_DCHECK_RUN_ON(signaling_thread_);
1806   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1807 
1808   for (const RtpTransceiverStatsInfo& stats : transceiver_stats_infos_) {
1809     std::vector<rtc::scoped_refptr<RtpSenderInternal>> senders;
1810     for (const auto& sender : stats.transceiver->senders()) {
1811       senders.push_back(
1812           rtc::scoped_refptr<RtpSenderInternal>(sender->internal()));
1813     }
1814     ProduceSenderMediaTrackStats(timestamp_us, stats.track_media_info_map,
1815                                  senders, report);
1816 
1817     std::vector<rtc::scoped_refptr<RtpReceiverInternal>> receivers;
1818     for (const auto& receiver : stats.transceiver->receivers()) {
1819       receivers.push_back(
1820           rtc::scoped_refptr<RtpReceiverInternal>(receiver->internal()));
1821     }
1822     ProduceReceiverMediaTrackStats(timestamp_us, stats.track_media_info_map,
1823                                    receivers, report);
1824   }
1825 }
1826 
ProduceMediaSourceStats_s(int64_t timestamp_us,RTCStatsReport * report) const1827 void RTCStatsCollector::ProduceMediaSourceStats_s(
1828     int64_t timestamp_us,
1829     RTCStatsReport* report) const {
1830   RTC_DCHECK_RUN_ON(signaling_thread_);
1831   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1832 
1833   for (const RtpTransceiverStatsInfo& transceiver_stats_info :
1834        transceiver_stats_infos_) {
1835     const auto& track_media_info_map =
1836         transceiver_stats_info.track_media_info_map;
1837     for (const auto& sender : transceiver_stats_info.transceiver->senders()) {
1838       const auto& sender_internal = sender->internal();
1839       const auto& track = sender_internal->track();
1840       if (!track)
1841         continue;
1842       // TODO(https://crbug.com/webrtc/10771): The same track could be attached
1843       // to multiple senders which should result in multiple senders referencing
1844       // the same media-source stats. When all media source related metrics are
1845       // moved to the track's source (e.g. input frame rate is moved from
1846       // cricket::VideoSenderInfo to VideoTrackSourceInterface::Stats and audio
1847       // levels are moved to the corresponding audio track/source object), don't
1848       // create separate media source stats objects on a per-attachment basis.
1849       std::unique_ptr<RTCMediaSourceStats> media_source_stats;
1850       if (track->kind() == MediaStreamTrackInterface::kAudioKind) {
1851         AudioTrackInterface* audio_track =
1852             static_cast<AudioTrackInterface*>(track.get());
1853         auto audio_source_stats = std::make_unique<RTCAudioSourceStats>(
1854             RTCMediaSourceStatsIDFromKindAndAttachment(
1855                 cricket::MEDIA_TYPE_AUDIO, sender_internal->AttachmentId()),
1856             timestamp_us);
1857         // TODO(https://crbug.com/webrtc/10771): We shouldn't need to have an
1858         // SSRC assigned (there shouldn't need to exist a send-stream, created
1859         // by an O/A exchange) in order to read audio media-source stats.
1860         // TODO(https://crbug.com/webrtc/8694): SSRC 0 shouldn't be a magic
1861         // value indicating no SSRC.
1862         if (sender_internal->ssrc() != 0) {
1863           auto* voice_sender_info =
1864               track_media_info_map.GetVoiceSenderInfoBySsrc(
1865                   sender_internal->ssrc());
1866           if (voice_sender_info) {
1867             audio_source_stats->audio_level = DoubleAudioLevelFromIntAudioLevel(
1868                 voice_sender_info->audio_level);
1869             audio_source_stats->total_audio_energy =
1870                 voice_sender_info->total_input_energy;
1871             audio_source_stats->total_samples_duration =
1872                 voice_sender_info->total_input_duration;
1873             SetAudioProcessingStats(audio_source_stats.get(),
1874                                     voice_sender_info->apm_statistics);
1875           }
1876         }
1877         // Audio processor may be attached to either the track or the send
1878         // stream, so look in both places.
1879         auto audio_processor(audio_track->GetAudioProcessor());
1880         if (audio_processor.get()) {
1881           // The `has_remote_tracks` argument is obsolete; makes no difference
1882           // if it's set to true or false.
1883           AudioProcessorInterface::AudioProcessorStatistics ap_stats =
1884               audio_processor->GetStats(/*has_remote_tracks=*/false);
1885           SetAudioProcessingStats(audio_source_stats.get(),
1886                                   ap_stats.apm_statistics);
1887         }
1888         media_source_stats = std::move(audio_source_stats);
1889       } else {
1890         RTC_DCHECK_EQ(MediaStreamTrackInterface::kVideoKind, track->kind());
1891         auto video_source_stats = std::make_unique<RTCVideoSourceStats>(
1892             RTCMediaSourceStatsIDFromKindAndAttachment(
1893                 cricket::MEDIA_TYPE_VIDEO, sender_internal->AttachmentId()),
1894             timestamp_us);
1895         auto* video_track = static_cast<VideoTrackInterface*>(track.get());
1896         auto* video_source = video_track->GetSource();
1897         VideoTrackSourceInterface::Stats source_stats;
1898         if (video_source && video_source->GetStats(&source_stats)) {
1899           video_source_stats->width = source_stats.input_width;
1900           video_source_stats->height = source_stats.input_height;
1901         }
1902         // TODO(https://crbug.com/webrtc/10771): We shouldn't need to have an
1903         // SSRC assigned (there shouldn't need to exist a send-stream, created
1904         // by an O/A exchange) in order to get framesPerSecond.
1905         // TODO(https://crbug.com/webrtc/8694): SSRC 0 shouldn't be a magic
1906         // value indicating no SSRC.
1907         if (sender_internal->ssrc() != 0) {
1908           auto* video_sender_info =
1909               track_media_info_map.GetVideoSenderInfoBySsrc(
1910                   sender_internal->ssrc());
1911           if (video_sender_info) {
1912             video_source_stats->frames_per_second =
1913                 video_sender_info->framerate_input;
1914             video_source_stats->frames = video_sender_info->frames;
1915           }
1916         }
1917         media_source_stats = std::move(video_source_stats);
1918       }
1919       media_source_stats->track_identifier = track->id();
1920       media_source_stats->kind = track->kind();
1921       report->AddStats(std::move(media_source_stats));
1922     }
1923   }
1924 }
1925 
ProducePeerConnectionStats_s(int64_t timestamp_us,RTCStatsReport * report) const1926 void RTCStatsCollector::ProducePeerConnectionStats_s(
1927     int64_t timestamp_us,
1928     RTCStatsReport* report) const {
1929   RTC_DCHECK_RUN_ON(signaling_thread_);
1930   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1931 
1932   std::unique_ptr<RTCPeerConnectionStats> stats(
1933       std::make_unique<RTCPeerConnectionStats>("P", timestamp_us));
1934   stats->data_channels_opened = internal_record_.data_channels_opened;
1935   stats->data_channels_closed = internal_record_.data_channels_closed;
1936   report->AddStats(std::move(stats));
1937 }
1938 
ProduceRTPStreamStats_n(int64_t timestamp_us,const std::vector<RtpTransceiverStatsInfo> & transceiver_stats_infos,RTCStatsReport * report) const1939 void RTCStatsCollector::ProduceRTPStreamStats_n(
1940     int64_t timestamp_us,
1941     const std::vector<RtpTransceiverStatsInfo>& transceiver_stats_infos,
1942     RTCStatsReport* report) const {
1943   RTC_DCHECK_RUN_ON(network_thread_);
1944   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1945 
1946   for (const RtpTransceiverStatsInfo& stats : transceiver_stats_infos) {
1947     if (stats.media_type == cricket::MEDIA_TYPE_AUDIO) {
1948       ProduceAudioRTPStreamStats_n(timestamp_us, stats, report);
1949     } else if (stats.media_type == cricket::MEDIA_TYPE_VIDEO) {
1950       ProduceVideoRTPStreamStats_n(timestamp_us, stats, report);
1951     } else {
1952       RTC_DCHECK_NOTREACHED();
1953     }
1954   }
1955 }
1956 
ProduceAudioRTPStreamStats_n(int64_t timestamp_us,const RtpTransceiverStatsInfo & stats,RTCStatsReport * report) const1957 void RTCStatsCollector::ProduceAudioRTPStreamStats_n(
1958     int64_t timestamp_us,
1959     const RtpTransceiverStatsInfo& stats,
1960     RTCStatsReport* report) const {
1961   RTC_DCHECK_RUN_ON(network_thread_);
1962   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1963 
1964   if (!stats.mid || !stats.transport_name) {
1965     return;
1966   }
1967   RTC_DCHECK(stats.track_media_info_map.voice_media_info().has_value());
1968   std::string mid = *stats.mid;
1969   std::string transport_id = RTCTransportStatsIDFromTransportChannel(
1970       *stats.transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
1971   // Inbound and remote-outbound.
1972   // The remote-outbound stats are based on RTCP sender reports sent from the
1973   // remote endpoint providing metrics about the remote outbound streams.
1974   for (const cricket::VoiceReceiverInfo& voice_receiver_info :
1975        stats.track_media_info_map.voice_media_info()->receivers) {
1976     if (!voice_receiver_info.connected())
1977       continue;
1978     // Inbound.
1979     auto inbound_audio = CreateInboundAudioStreamStats(
1980         stats.track_media_info_map.voice_media_info().value(),
1981         voice_receiver_info, transport_id, mid, timestamp_us, report);
1982     // TODO(hta): This lookup should look for the sender, not the track.
1983     rtc::scoped_refptr<AudioTrackInterface> audio_track =
1984         stats.track_media_info_map.GetAudioTrack(voice_receiver_info);
1985     if (audio_track) {
1986       inbound_audio->track_id =
1987           DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
1988               kDirectionInbound, stats.track_media_info_map
1989                                      .GetAttachmentIdByTrack(audio_track.get())
1990                                      .value());
1991       inbound_audio->track_identifier = audio_track->id();
1992     }
1993     auto* inbound_audio_ptr = report->TryAddStats(std::move(inbound_audio));
1994     if (!inbound_audio_ptr) {
1995       RTC_LOG(LS_ERROR)
1996           << "Unable to add audio 'inbound-rtp' to report, ID is not unique.";
1997       continue;
1998     }
1999     // Remote-outbound.
2000     auto remote_outbound_audio = CreateRemoteOutboundAudioStreamStats(
2001         voice_receiver_info, mid, *inbound_audio_ptr, transport_id);
2002     // Add stats.
2003     if (remote_outbound_audio) {
2004       // When the remote outbound stats are available, the remote ID for the
2005       // local inbound stats is set.
2006       auto* remote_outbound_audio_ptr =
2007           report->TryAddStats(std::move(remote_outbound_audio));
2008       if (remote_outbound_audio_ptr) {
2009         inbound_audio_ptr->remote_id = remote_outbound_audio_ptr->id();
2010       } else {
2011         RTC_LOG(LS_ERROR) << "Unable to add audio 'remote-outbound-rtp' to "
2012                           << "report, ID is not unique.";
2013       }
2014     }
2015   }
2016   // Outbound.
2017   std::map<std::string, RTCOutboundRTPStreamStats*> audio_outbound_rtps;
2018   for (const cricket::VoiceSenderInfo& voice_sender_info :
2019        stats.track_media_info_map.voice_media_info()->senders) {
2020     if (!voice_sender_info.connected())
2021       continue;
2022     auto outbound_audio = std::make_unique<RTCOutboundRTPStreamStats>(
2023         RTCOutboundRTPStreamStatsIDFromSSRC(
2024             transport_id, cricket::MEDIA_TYPE_AUDIO, voice_sender_info.ssrc()),
2025         timestamp_us);
2026     SetOutboundRTPStreamStatsFromVoiceSenderInfo(
2027         transport_id, mid,
2028         stats.track_media_info_map.voice_media_info().value(),
2029         voice_sender_info, outbound_audio.get(), report);
2030     rtc::scoped_refptr<AudioTrackInterface> audio_track =
2031         stats.track_media_info_map.GetAudioTrack(voice_sender_info);
2032     if (audio_track) {
2033       int attachment_id =
2034           stats.track_media_info_map.GetAttachmentIdByTrack(audio_track.get())
2035               .value();
2036       outbound_audio->track_id =
2037           DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
2038               kDirectionOutbound, attachment_id);
2039       outbound_audio->media_source_id =
2040           RTCMediaSourceStatsIDFromKindAndAttachment(cricket::MEDIA_TYPE_AUDIO,
2041                                                      attachment_id);
2042     }
2043     auto audio_outbound_pair =
2044         std::make_pair(outbound_audio->id(), outbound_audio.get());
2045     if (report->TryAddStats(std::move(outbound_audio))) {
2046       audio_outbound_rtps.insert(std::move(audio_outbound_pair));
2047     } else {
2048       RTC_LOG(LS_ERROR)
2049           << "Unable to add audio 'outbound-rtp' to report, ID is not unique.";
2050     }
2051   }
2052   // Remote-inbound.
2053   // These are Report Block-based, information sent from the remote endpoint,
2054   // providing metrics about our Outbound streams. We take advantage of the fact
2055   // that RTCOutboundRtpStreamStats, RTCCodecStats and RTCTransport have already
2056   // been added to the report.
2057   for (const cricket::VoiceSenderInfo& voice_sender_info :
2058        stats.track_media_info_map.voice_media_info()->senders) {
2059     for (const auto& report_block_data : voice_sender_info.report_block_datas) {
2060       report->AddStats(ProduceRemoteInboundRtpStreamStatsFromReportBlockData(
2061           transport_id, report_block_data, cricket::MEDIA_TYPE_AUDIO,
2062           audio_outbound_rtps, *report));
2063     }
2064   }
2065 }
2066 
ProduceVideoRTPStreamStats_n(int64_t timestamp_us,const RtpTransceiverStatsInfo & stats,RTCStatsReport * report) const2067 void RTCStatsCollector::ProduceVideoRTPStreamStats_n(
2068     int64_t timestamp_us,
2069     const RtpTransceiverStatsInfo& stats,
2070     RTCStatsReport* report) const {
2071   RTC_DCHECK_RUN_ON(network_thread_);
2072   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
2073 
2074   if (!stats.mid || !stats.transport_name) {
2075     return;
2076   }
2077   RTC_DCHECK(stats.track_media_info_map.video_media_info().has_value());
2078   std::string mid = *stats.mid;
2079   std::string transport_id = RTCTransportStatsIDFromTransportChannel(
2080       *stats.transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
2081   // Inbound
2082   for (const cricket::VideoReceiverInfo& video_receiver_info :
2083        stats.track_media_info_map.video_media_info()->receivers) {
2084     if (!video_receiver_info.connected())
2085       continue;
2086     auto inbound_video = std::make_unique<RTCInboundRTPStreamStats>(
2087         RTCInboundRTPStreamStatsIDFromSSRC(transport_id,
2088                                            cricket::MEDIA_TYPE_VIDEO,
2089                                            video_receiver_info.ssrc()),
2090         timestamp_us);
2091     SetInboundRTPStreamStatsFromVideoReceiverInfo(
2092         transport_id, mid,
2093         stats.track_media_info_map.video_media_info().value(),
2094         video_receiver_info, inbound_video.get(), report);
2095     rtc::scoped_refptr<VideoTrackInterface> video_track =
2096         stats.track_media_info_map.GetVideoTrack(video_receiver_info);
2097     if (video_track) {
2098       inbound_video->track_id =
2099           DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
2100               kDirectionInbound, stats.track_media_info_map
2101                                      .GetAttachmentIdByTrack(video_track.get())
2102                                      .value());
2103       inbound_video->track_identifier = video_track->id();
2104     }
2105     if (!report->TryAddStats(std::move(inbound_video))) {
2106       RTC_LOG(LS_ERROR)
2107           << "Unable to add video 'inbound-rtp' to report, ID is not unique.";
2108     }
2109   }
2110   // Outbound
2111   std::map<std::string, RTCOutboundRTPStreamStats*> video_outbound_rtps;
2112   for (const cricket::VideoSenderInfo& video_sender_info :
2113        stats.track_media_info_map.video_media_info()->senders) {
2114     if (!video_sender_info.connected())
2115       continue;
2116     auto outbound_video = std::make_unique<RTCOutboundRTPStreamStats>(
2117         RTCOutboundRTPStreamStatsIDFromSSRC(
2118             transport_id, cricket::MEDIA_TYPE_VIDEO, video_sender_info.ssrc()),
2119         timestamp_us);
2120     SetOutboundRTPStreamStatsFromVideoSenderInfo(
2121         transport_id, mid,
2122         stats.track_media_info_map.video_media_info().value(),
2123         video_sender_info, outbound_video.get(), report);
2124     rtc::scoped_refptr<VideoTrackInterface> video_track =
2125         stats.track_media_info_map.GetVideoTrack(video_sender_info);
2126     if (video_track) {
2127       int attachment_id =
2128           stats.track_media_info_map.GetAttachmentIdByTrack(video_track.get())
2129               .value();
2130       outbound_video->track_id =
2131           DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
2132               kDirectionOutbound, attachment_id);
2133       outbound_video->media_source_id =
2134           RTCMediaSourceStatsIDFromKindAndAttachment(cricket::MEDIA_TYPE_VIDEO,
2135                                                      attachment_id);
2136     }
2137     auto video_outbound_pair =
2138         std::make_pair(outbound_video->id(), outbound_video.get());
2139     if (report->TryAddStats(std::move(outbound_video))) {
2140       video_outbound_rtps.insert(std::move(video_outbound_pair));
2141     } else {
2142       RTC_LOG(LS_ERROR)
2143           << "Unable to add video 'outbound-rtp' to report, ID is not unique.";
2144     }
2145   }
2146   // Remote-inbound
2147   // These are Report Block-based, information sent from the remote endpoint,
2148   // providing metrics about our Outbound streams. We take advantage of the fact
2149   // that RTCOutboundRtpStreamStats, RTCCodecStats and RTCTransport have already
2150   // been added to the report.
2151   for (const cricket::VideoSenderInfo& video_sender_info :
2152        stats.track_media_info_map.video_media_info()->senders) {
2153     for (const auto& report_block_data : video_sender_info.report_block_datas) {
2154       report->AddStats(ProduceRemoteInboundRtpStreamStatsFromReportBlockData(
2155           transport_id, report_block_data, cricket::MEDIA_TYPE_VIDEO,
2156           video_outbound_rtps, *report));
2157     }
2158   }
2159 }
2160 
ProduceTransportStats_n(int64_t timestamp_us,const std::map<std::string,cricket::TransportStats> & transport_stats_by_name,const std::map<std::string,CertificateStatsPair> & transport_cert_stats,RTCStatsReport * report) const2161 void RTCStatsCollector::ProduceTransportStats_n(
2162     int64_t timestamp_us,
2163     const std::map<std::string, cricket::TransportStats>&
2164         transport_stats_by_name,
2165     const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
2166     RTCStatsReport* report) const {
2167   RTC_DCHECK_RUN_ON(network_thread_);
2168   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
2169 
2170   for (const auto& entry : transport_stats_by_name) {
2171     const std::string& transport_name = entry.first;
2172     const cricket::TransportStats& transport_stats = entry.second;
2173 
2174     // Get reference to RTCP channel, if it exists.
2175     std::string rtcp_transport_stats_id;
2176     for (const cricket::TransportChannelStats& channel_stats :
2177          transport_stats.channel_stats) {
2178       if (channel_stats.component == cricket::ICE_CANDIDATE_COMPONENT_RTCP) {
2179         rtcp_transport_stats_id = RTCTransportStatsIDFromTransportChannel(
2180             transport_name, channel_stats.component);
2181         break;
2182       }
2183     }
2184 
2185     // Get reference to local and remote certificates of this transport, if they
2186     // exist.
2187     const auto& certificate_stats_it =
2188         transport_cert_stats.find(transport_name);
2189     RTC_DCHECK(certificate_stats_it != transport_cert_stats.cend());
2190     std::string local_certificate_id;
2191     if (certificate_stats_it->second.local) {
2192       local_certificate_id = RTCCertificateIDFromFingerprint(
2193           certificate_stats_it->second.local->fingerprint);
2194     }
2195     std::string remote_certificate_id;
2196     if (certificate_stats_it->second.remote) {
2197       remote_certificate_id = RTCCertificateIDFromFingerprint(
2198           certificate_stats_it->second.remote->fingerprint);
2199     }
2200 
2201     // There is one transport stats for each channel.
2202     for (const cricket::TransportChannelStats& channel_stats :
2203          transport_stats.channel_stats) {
2204       std::unique_ptr<RTCTransportStats> transport_stats(
2205           std::make_unique<RTCTransportStats>(
2206               RTCTransportStatsIDFromTransportChannel(transport_name,
2207                                                       channel_stats.component),
2208               timestamp_us));
2209       transport_stats->packets_sent =
2210           channel_stats.ice_transport_stats.packets_sent;
2211       transport_stats->packets_received =
2212           channel_stats.ice_transport_stats.packets_received;
2213       transport_stats->bytes_sent =
2214           channel_stats.ice_transport_stats.bytes_sent;
2215       transport_stats->bytes_received =
2216           channel_stats.ice_transport_stats.bytes_received;
2217       transport_stats->dtls_state =
2218           DtlsTransportStateToRTCDtlsTransportState(channel_stats.dtls_state);
2219       transport_stats->selected_candidate_pair_changes =
2220           channel_stats.ice_transport_stats.selected_candidate_pair_changes;
2221       transport_stats->ice_role =
2222           IceRoleToRTCIceRole(channel_stats.ice_transport_stats.ice_role);
2223       transport_stats->ice_local_username_fragment =
2224           channel_stats.ice_transport_stats.ice_local_username_fragment;
2225       transport_stats->ice_state = IceTransportStateToRTCIceTransportState(
2226           channel_stats.ice_transport_stats.ice_state);
2227       for (const cricket::ConnectionInfo& info :
2228            channel_stats.ice_transport_stats.connection_infos) {
2229         if (info.best_connection) {
2230           transport_stats->selected_candidate_pair_id =
2231               RTCIceCandidatePairStatsIDFromConnectionInfo(info);
2232         }
2233       }
2234       if (channel_stats.component != cricket::ICE_CANDIDATE_COMPONENT_RTCP &&
2235           !rtcp_transport_stats_id.empty()) {
2236         transport_stats->rtcp_transport_stats_id = rtcp_transport_stats_id;
2237       }
2238       if (!local_certificate_id.empty())
2239         transport_stats->local_certificate_id = local_certificate_id;
2240       if (!remote_certificate_id.empty())
2241         transport_stats->remote_certificate_id = remote_certificate_id;
2242       // Crypto information
2243       if (channel_stats.ssl_version_bytes) {
2244         char bytes[5];
2245         snprintf(bytes, sizeof(bytes), "%04X", channel_stats.ssl_version_bytes);
2246         transport_stats->tls_version = bytes;
2247       }
2248 
2249       if (channel_stats.dtls_role) {
2250         transport_stats->dtls_role = *channel_stats.dtls_role == rtc::SSL_CLIENT
2251                                          ? webrtc::RTCDtlsRole::kClient
2252                                          : webrtc::RTCDtlsRole::kServer;
2253       } else {
2254         transport_stats->dtls_role = webrtc::RTCDtlsRole::kUnknown;
2255       }
2256 
2257       if (channel_stats.ssl_cipher_suite != rtc::kTlsNullWithNullNull &&
2258           rtc::SSLStreamAdapter::SslCipherSuiteToName(
2259               channel_stats.ssl_cipher_suite)
2260               .length()) {
2261         transport_stats->dtls_cipher =
2262             rtc::SSLStreamAdapter::SslCipherSuiteToName(
2263                 channel_stats.ssl_cipher_suite);
2264       }
2265       if (channel_stats.srtp_crypto_suite != rtc::kSrtpInvalidCryptoSuite &&
2266           rtc::SrtpCryptoSuiteToName(channel_stats.srtp_crypto_suite)
2267               .length()) {
2268         transport_stats->srtp_cipher =
2269             rtc::SrtpCryptoSuiteToName(channel_stats.srtp_crypto_suite);
2270       }
2271       report->AddStats(std::move(transport_stats));
2272     }
2273   }
2274 }
2275 
2276 std::map<std::string, RTCStatsCollector::CertificateStatsPair>
PrepareTransportCertificateStats_n(const std::map<std::string,cricket::TransportStats> & transport_stats_by_name)2277 RTCStatsCollector::PrepareTransportCertificateStats_n(
2278     const std::map<std::string, cricket::TransportStats>&
2279         transport_stats_by_name) {
2280   RTC_DCHECK_RUN_ON(network_thread_);
2281   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
2282 
2283   std::map<std::string, CertificateStatsPair> transport_cert_stats;
2284   {
2285     MutexLock lock(&cached_certificates_mutex_);
2286     // Copy the certificate info from the cache, avoiding expensive
2287     // rtc::SSLCertChain::GetStats() calls.
2288     for (const auto& pair : cached_certificates_by_transport_) {
2289       transport_cert_stats.insert(
2290           std::make_pair(pair.first, pair.second.Copy()));
2291     }
2292   }
2293   if (transport_cert_stats.empty()) {
2294     // Collect certificate info.
2295     for (const auto& entry : transport_stats_by_name) {
2296       const std::string& transport_name = entry.first;
2297 
2298       CertificateStatsPair certificate_stats_pair;
2299       rtc::scoped_refptr<rtc::RTCCertificate> local_certificate;
2300       if (pc_->GetLocalCertificate(transport_name, &local_certificate)) {
2301         certificate_stats_pair.local =
2302             local_certificate->GetSSLCertificateChain().GetStats();
2303       }
2304 
2305       std::unique_ptr<rtc::SSLCertChain> remote_cert_chain =
2306           pc_->GetRemoteSSLCertChain(transport_name);
2307       if (remote_cert_chain) {
2308         certificate_stats_pair.remote = remote_cert_chain->GetStats();
2309       }
2310 
2311       transport_cert_stats.insert(
2312           std::make_pair(transport_name, std::move(certificate_stats_pair)));
2313     }
2314     // Copy the result into the certificate cache for future reference.
2315     MutexLock lock(&cached_certificates_mutex_);
2316     for (const auto& pair : transport_cert_stats) {
2317       cached_certificates_by_transport_.insert(
2318           std::make_pair(pair.first, pair.second.Copy()));
2319     }
2320   }
2321   return transport_cert_stats;
2322 }
2323 
PrepareTransceiverStatsInfosAndCallStats_s_w_n()2324 void RTCStatsCollector::PrepareTransceiverStatsInfosAndCallStats_s_w_n() {
2325   RTC_DCHECK_RUN_ON(signaling_thread_);
2326 
2327   transceiver_stats_infos_.clear();
2328   // These are used to invoke GetStats for all the media channels together in
2329   // one worker thread hop.
2330   std::map<cricket::VoiceMediaChannel*, cricket::VoiceMediaInfo> voice_stats;
2331   std::map<cricket::VideoMediaChannel*, cricket::VideoMediaInfo> video_stats;
2332 
2333   auto transceivers = pc_->GetTransceiversInternal();
2334 
2335   // TODO(tommi): See if we can avoid synchronously blocking the signaling
2336   // thread while we do this (or avoid the BlockingCall at all).
2337   network_thread_->BlockingCall([this, &transceivers, &voice_stats,
2338                                  &video_stats] {
2339     rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
2340 
2341     for (const auto& transceiver_proxy : transceivers) {
2342       RtpTransceiver* transceiver = transceiver_proxy->internal();
2343       cricket::MediaType media_type = transceiver->media_type();
2344 
2345       // Prepare stats entry. The TrackMediaInfoMap will be filled in after the
2346       // stats have been fetched on the worker thread.
2347       transceiver_stats_infos_.emplace_back();
2348       RtpTransceiverStatsInfo& stats = transceiver_stats_infos_.back();
2349       stats.transceiver = transceiver;
2350       stats.media_type = media_type;
2351 
2352       cricket::ChannelInterface* channel = transceiver->channel();
2353       if (!channel) {
2354         // The remaining fields require a BaseChannel.
2355         continue;
2356       }
2357 
2358       stats.mid = channel->mid();
2359       stats.transport_name = std::string(channel->transport_name());
2360 
2361       if (media_type == cricket::MEDIA_TYPE_AUDIO) {
2362         cricket::VoiceMediaChannel* voice_channel =
2363             static_cast<cricket::VoiceMediaChannel*>(channel->media_channel());
2364         RTC_DCHECK(voice_stats.find(voice_channel) == voice_stats.end());
2365         voice_stats.insert(
2366             std::make_pair(voice_channel, cricket::VoiceMediaInfo()));
2367       } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
2368         cricket::VideoMediaChannel* video_channel =
2369             static_cast<cricket::VideoMediaChannel*>(channel->media_channel());
2370         RTC_DCHECK(video_stats.find(video_channel) == video_stats.end());
2371         video_stats.insert(
2372             std::make_pair(video_channel, cricket::VideoMediaInfo()));
2373       } else {
2374         RTC_DCHECK_NOTREACHED();
2375       }
2376     }
2377   });
2378 
2379   // We jump to the worker thread and call GetStats() on each media channel as
2380   // well as GetCallStats(). At the same time we construct the
2381   // TrackMediaInfoMaps, which also needs info from the worker thread. This
2382   // minimizes the number of thread jumps.
2383   worker_thread_->BlockingCall([&] {
2384     rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
2385 
2386     for (auto& pair : voice_stats) {
2387       if (!pair.first->GetStats(&pair.second,
2388                                 /*get_and_clear_legacy_stats=*/false)) {
2389         RTC_LOG(LS_WARNING) << "Failed to get voice stats.";
2390       }
2391     }
2392     for (auto& pair : video_stats) {
2393       if (!pair.first->GetStats(&pair.second)) {
2394         RTC_LOG(LS_WARNING) << "Failed to get video stats.";
2395       }
2396     }
2397 
2398     // Create the TrackMediaInfoMap for each transceiver stats object.
2399     for (auto& stats : transceiver_stats_infos_) {
2400       auto transceiver = stats.transceiver;
2401       absl::optional<cricket::VoiceMediaInfo> voice_media_info;
2402       absl::optional<cricket::VideoMediaInfo> video_media_info;
2403       auto channel = transceiver->channel();
2404       if (channel) {
2405         cricket::MediaType media_type = transceiver->media_type();
2406         if (media_type == cricket::MEDIA_TYPE_AUDIO) {
2407           cricket::VoiceMediaChannel* voice_channel =
2408               static_cast<cricket::VoiceMediaChannel*>(
2409                   channel->media_channel());
2410           RTC_DCHECK(voice_stats.find(voice_channel) != voice_stats.end());
2411           voice_media_info = std::move(voice_stats[voice_channel]);
2412         } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
2413           cricket::VideoMediaChannel* video_channel =
2414               static_cast<cricket::VideoMediaChannel*>(
2415                   channel->media_channel());
2416           RTC_DCHECK(video_stats.find(video_channel) != video_stats.end());
2417           video_media_info = std::move(video_stats[video_channel]);
2418         }
2419       }
2420       std::vector<rtc::scoped_refptr<RtpSenderInternal>> senders;
2421       for (const auto& sender : transceiver->senders()) {
2422         senders.push_back(
2423             rtc::scoped_refptr<RtpSenderInternal>(sender->internal()));
2424       }
2425       std::vector<rtc::scoped_refptr<RtpReceiverInternal>> receivers;
2426       for (const auto& receiver : transceiver->receivers()) {
2427         receivers.push_back(
2428             rtc::scoped_refptr<RtpReceiverInternal>(receiver->internal()));
2429       }
2430       stats.track_media_info_map.Initialize(std::move(voice_media_info),
2431                                             std::move(video_media_info),
2432                                             senders, receivers);
2433     }
2434 
2435     call_stats_ = pc_->GetCallStats();
2436   });
2437 }
2438 
OnSctpDataChannelCreated(SctpDataChannel * channel)2439 void RTCStatsCollector::OnSctpDataChannelCreated(SctpDataChannel* channel) {
2440   channel->SignalOpened.connect(this, &RTCStatsCollector::OnDataChannelOpened);
2441   channel->SignalClosed.connect(this, &RTCStatsCollector::OnDataChannelClosed);
2442 }
2443 
OnDataChannelOpened(DataChannelInterface * channel)2444 void RTCStatsCollector::OnDataChannelOpened(DataChannelInterface* channel) {
2445   RTC_DCHECK_RUN_ON(signaling_thread_);
2446   bool result = internal_record_.opened_data_channels
2447                     .insert(reinterpret_cast<uintptr_t>(channel))
2448                     .second;
2449   ++internal_record_.data_channels_opened;
2450   RTC_DCHECK(result);
2451 }
2452 
OnDataChannelClosed(DataChannelInterface * channel)2453 void RTCStatsCollector::OnDataChannelClosed(DataChannelInterface* channel) {
2454   RTC_DCHECK_RUN_ON(signaling_thread_);
2455   // Only channels that have been fully opened (and have increased the
2456   // `data_channels_opened_` counter) increase the closed counter.
2457   if (internal_record_.opened_data_channels.erase(
2458           reinterpret_cast<uintptr_t>(channel))) {
2459     ++internal_record_.data_channels_closed;
2460   }
2461 }
2462 
CandidateTypeToRTCIceCandidateTypeForTesting(const std::string & type)2463 const char* CandidateTypeToRTCIceCandidateTypeForTesting(
2464     const std::string& type) {
2465   return CandidateTypeToRTCIceCandidateType(type);
2466 }
2467 
DataStateToRTCDataChannelStateForTesting(DataChannelInterface::DataState state)2468 const char* DataStateToRTCDataChannelStateForTesting(
2469     DataChannelInterface::DataState state) {
2470   return DataStateToRTCDataChannelState(state);
2471 }
2472 
2473 }  // namespace webrtc
2474