• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <map>
14 #include <memory>
15 #include <string>
16 #include <utility>
17 #include <vector>
18 
19 #include "api/candidate.h"
20 #include "api/media_stream_interface.h"
21 #include "api/peer_connection_interface.h"
22 #include "api/video/video_content_type.h"
23 #include "media/base/media_channel.h"
24 #include "p2p/base/p2p_constants.h"
25 #include "p2p/base/port.h"
26 #include "pc/peer_connection.h"
27 #include "pc/rtc_stats_traversal.h"
28 #include "pc/webrtc_sdp.h"
29 #include "rtc_base/checks.h"
30 #include "rtc_base/strings/string_builder.h"
31 #include "rtc_base/time_utils.h"
32 #include "rtc_base/trace_event.h"
33 
34 namespace webrtc {
35 
36 namespace {
37 
38 // TODO(https://crbug.com/webrtc/10656): Consider making IDs less predictable.
RTCCertificateIDFromFingerprint(const std::string & fingerprint)39 std::string RTCCertificateIDFromFingerprint(const std::string& fingerprint) {
40   return "RTCCertificate_" + fingerprint;
41 }
42 
RTCCodecStatsIDFromMidDirectionAndPayload(const std::string & mid,bool inbound,uint32_t payload_type)43 std::string RTCCodecStatsIDFromMidDirectionAndPayload(const std::string& mid,
44                                                       bool inbound,
45                                                       uint32_t payload_type) {
46   char buf[1024];
47   rtc::SimpleStringBuilder sb(buf);
48   sb << "RTCCodec_" << mid << (inbound ? "_Inbound_" : "_Outbound_")
49      << payload_type;
50   return sb.str();
51 }
52 
RTCIceCandidatePairStatsIDFromConnectionInfo(const cricket::ConnectionInfo & info)53 std::string RTCIceCandidatePairStatsIDFromConnectionInfo(
54     const cricket::ConnectionInfo& info) {
55   char buf[4096];
56   rtc::SimpleStringBuilder sb(buf);
57   sb << "RTCIceCandidatePair_" << info.local_candidate.id() << "_"
58      << info.remote_candidate.id();
59   return sb.str();
60 }
61 
62 const char kSender[] = "sender";
63 const char kReceiver[] = "receiver";
64 
RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(const char * direction,int attachment_id)65 std::string RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
66     const char* direction,
67     int attachment_id) {
68   char buf[1024];
69   rtc::SimpleStringBuilder sb(buf);
70   sb << "RTCMediaStreamTrack_" << direction << "_" << attachment_id;
71   return sb.str();
72 }
73 
RTCTransportStatsIDFromTransportChannel(const std::string & transport_name,int channel_component)74 std::string RTCTransportStatsIDFromTransportChannel(
75     const std::string& transport_name,
76     int channel_component) {
77   char buf[1024];
78   rtc::SimpleStringBuilder sb(buf);
79   sb << "RTCTransport_" << transport_name << "_" << channel_component;
80   return sb.str();
81 }
82 
RTCInboundRTPStreamStatsIDFromSSRC(bool audio,uint32_t ssrc)83 std::string RTCInboundRTPStreamStatsIDFromSSRC(bool audio, uint32_t ssrc) {
84   char buf[1024];
85   rtc::SimpleStringBuilder sb(buf);
86   sb << "RTCInboundRTP" << (audio ? "Audio" : "Video") << "Stream_" << ssrc;
87   return sb.str();
88 }
89 
RTCOutboundRTPStreamStatsIDFromSSRC(bool audio,uint32_t ssrc)90 std::string RTCOutboundRTPStreamStatsIDFromSSRC(bool audio, uint32_t ssrc) {
91   char buf[1024];
92   rtc::SimpleStringBuilder sb(buf);
93   sb << "RTCOutboundRTP" << (audio ? "Audio" : "Video") << "Stream_" << ssrc;
94   return sb.str();
95 }
96 
RTCRemoteInboundRtpStreamStatsIdFromSourceSsrc(cricket::MediaType media_type,uint32_t source_ssrc)97 std::string RTCRemoteInboundRtpStreamStatsIdFromSourceSsrc(
98     cricket::MediaType media_type,
99     uint32_t source_ssrc) {
100   char buf[1024];
101   rtc::SimpleStringBuilder sb(buf);
102   sb << "RTCRemoteInboundRtp"
103      << (media_type == cricket::MEDIA_TYPE_AUDIO ? "Audio" : "Video")
104      << "Stream_" << source_ssrc;
105   return sb.str();
106 }
107 
RTCMediaSourceStatsIDFromKindAndAttachment(cricket::MediaType media_type,int attachment_id)108 std::string RTCMediaSourceStatsIDFromKindAndAttachment(
109     cricket::MediaType media_type,
110     int attachment_id) {
111   char buf[1024];
112   rtc::SimpleStringBuilder sb(buf);
113   sb << "RTC" << (media_type == cricket::MEDIA_TYPE_AUDIO ? "Audio" : "Video")
114      << "Source_" << attachment_id;
115   return sb.str();
116 }
117 
CandidateTypeToRTCIceCandidateType(const std::string & type)118 const char* CandidateTypeToRTCIceCandidateType(const std::string& type) {
119   if (type == cricket::LOCAL_PORT_TYPE)
120     return RTCIceCandidateType::kHost;
121   if (type == cricket::STUN_PORT_TYPE)
122     return RTCIceCandidateType::kSrflx;
123   if (type == cricket::PRFLX_PORT_TYPE)
124     return RTCIceCandidateType::kPrflx;
125   if (type == cricket::RELAY_PORT_TYPE)
126     return RTCIceCandidateType::kRelay;
127   RTC_NOTREACHED();
128   return nullptr;
129 }
130 
DataStateToRTCDataChannelState(DataChannelInterface::DataState state)131 const char* DataStateToRTCDataChannelState(
132     DataChannelInterface::DataState state) {
133   switch (state) {
134     case DataChannelInterface::kConnecting:
135       return RTCDataChannelState::kConnecting;
136     case DataChannelInterface::kOpen:
137       return RTCDataChannelState::kOpen;
138     case DataChannelInterface::kClosing:
139       return RTCDataChannelState::kClosing;
140     case DataChannelInterface::kClosed:
141       return RTCDataChannelState::kClosed;
142     default:
143       RTC_NOTREACHED();
144       return nullptr;
145   }
146 }
147 
IceCandidatePairStateToRTCStatsIceCandidatePairState(cricket::IceCandidatePairState state)148 const char* IceCandidatePairStateToRTCStatsIceCandidatePairState(
149     cricket::IceCandidatePairState state) {
150   switch (state) {
151     case cricket::IceCandidatePairState::WAITING:
152       return RTCStatsIceCandidatePairState::kWaiting;
153     case cricket::IceCandidatePairState::IN_PROGRESS:
154       return RTCStatsIceCandidatePairState::kInProgress;
155     case cricket::IceCandidatePairState::SUCCEEDED:
156       return RTCStatsIceCandidatePairState::kSucceeded;
157     case cricket::IceCandidatePairState::FAILED:
158       return RTCStatsIceCandidatePairState::kFailed;
159     default:
160       RTC_NOTREACHED();
161       return nullptr;
162   }
163 }
164 
DtlsTransportStateToRTCDtlsTransportState(cricket::DtlsTransportState state)165 const char* DtlsTransportStateToRTCDtlsTransportState(
166     cricket::DtlsTransportState state) {
167   switch (state) {
168     case cricket::DTLS_TRANSPORT_NEW:
169       return RTCDtlsTransportState::kNew;
170     case cricket::DTLS_TRANSPORT_CONNECTING:
171       return RTCDtlsTransportState::kConnecting;
172     case cricket::DTLS_TRANSPORT_CONNECTED:
173       return RTCDtlsTransportState::kConnected;
174     case cricket::DTLS_TRANSPORT_CLOSED:
175       return RTCDtlsTransportState::kClosed;
176     case cricket::DTLS_TRANSPORT_FAILED:
177       return RTCDtlsTransportState::kFailed;
178     default:
179       RTC_NOTREACHED();
180       return nullptr;
181   }
182 }
183 
NetworkAdapterTypeToStatsType(rtc::AdapterType type)184 const char* NetworkAdapterTypeToStatsType(rtc::AdapterType type) {
185   switch (type) {
186     case rtc::ADAPTER_TYPE_CELLULAR:
187     case rtc::ADAPTER_TYPE_CELLULAR_2G:
188     case rtc::ADAPTER_TYPE_CELLULAR_3G:
189     case rtc::ADAPTER_TYPE_CELLULAR_4G:
190     case rtc::ADAPTER_TYPE_CELLULAR_5G:
191       return RTCNetworkType::kCellular;
192     case rtc::ADAPTER_TYPE_ETHERNET:
193       return RTCNetworkType::kEthernet;
194     case rtc::ADAPTER_TYPE_WIFI:
195       return RTCNetworkType::kWifi;
196     case rtc::ADAPTER_TYPE_VPN:
197       return RTCNetworkType::kVpn;
198     case rtc::ADAPTER_TYPE_UNKNOWN:
199     case rtc::ADAPTER_TYPE_LOOPBACK:
200     case rtc::ADAPTER_TYPE_ANY:
201       return RTCNetworkType::kUnknown;
202   }
203   RTC_NOTREACHED();
204   return nullptr;
205 }
206 
QualityLimitationReasonToRTCQualityLimitationReason(QualityLimitationReason reason)207 const char* QualityLimitationReasonToRTCQualityLimitationReason(
208     QualityLimitationReason reason) {
209   switch (reason) {
210     case QualityLimitationReason::kNone:
211       return RTCQualityLimitationReason::kNone;
212     case QualityLimitationReason::kCpu:
213       return RTCQualityLimitationReason::kCpu;
214     case QualityLimitationReason::kBandwidth:
215       return RTCQualityLimitationReason::kBandwidth;
216     case QualityLimitationReason::kOther:
217       return RTCQualityLimitationReason::kOther;
218   }
219 }
220 
DoubleAudioLevelFromIntAudioLevel(int audio_level)221 double DoubleAudioLevelFromIntAudioLevel(int audio_level) {
222   RTC_DCHECK_GE(audio_level, 0);
223   RTC_DCHECK_LE(audio_level, 32767);
224   return audio_level / 32767.0;
225 }
226 
CodecStatsFromRtpCodecParameters(uint64_t timestamp_us,const std::string & mid,bool inbound,const RtpCodecParameters & codec_params)227 std::unique_ptr<RTCCodecStats> CodecStatsFromRtpCodecParameters(
228     uint64_t timestamp_us,
229     const std::string& mid,
230     bool inbound,
231     const RtpCodecParameters& codec_params) {
232   RTC_DCHECK_GE(codec_params.payload_type, 0);
233   RTC_DCHECK_LE(codec_params.payload_type, 127);
234   RTC_DCHECK(codec_params.clock_rate);
235   uint32_t payload_type = static_cast<uint32_t>(codec_params.payload_type);
236   std::unique_ptr<RTCCodecStats> codec_stats(new RTCCodecStats(
237       RTCCodecStatsIDFromMidDirectionAndPayload(mid, inbound, payload_type),
238       timestamp_us));
239   codec_stats->payload_type = payload_type;
240   codec_stats->mime_type = codec_params.mime_type();
241   if (codec_params.clock_rate) {
242     codec_stats->clock_rate = static_cast<uint32_t>(*codec_params.clock_rate);
243   }
244   if (codec_params.num_channels) {
245     codec_stats->channels = *codec_params.num_channels;
246   }
247 
248   rtc::StringBuilder fmtp;
249   if (WriteFmtpParameters(codec_params.parameters, &fmtp)) {
250     codec_stats->sdp_fmtp_line = fmtp.Release();
251   }
252   return codec_stats;
253 }
254 
SetMediaStreamTrackStatsFromMediaStreamTrackInterface(const MediaStreamTrackInterface & track,RTCMediaStreamTrackStats * track_stats)255 void SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
256     const MediaStreamTrackInterface& track,
257     RTCMediaStreamTrackStats* track_stats) {
258   track_stats->track_identifier = track.id();
259   track_stats->ended = (track.state() == MediaStreamTrackInterface::kEnded);
260 }
261 
262 // Provides the media independent counters (both audio and video).
SetInboundRTPStreamStatsFromMediaReceiverInfo(const cricket::MediaReceiverInfo & media_receiver_info,RTCInboundRTPStreamStats * inbound_stats)263 void SetInboundRTPStreamStatsFromMediaReceiverInfo(
264     const cricket::MediaReceiverInfo& media_receiver_info,
265     RTCInboundRTPStreamStats* inbound_stats) {
266   RTC_DCHECK(inbound_stats);
267   inbound_stats->ssrc = media_receiver_info.ssrc();
268   // TODO(hbos): Support the remote case. https://crbug.com/657855
269   inbound_stats->is_remote = false;
270   inbound_stats->packets_received =
271       static_cast<uint32_t>(media_receiver_info.packets_rcvd);
272   inbound_stats->bytes_received =
273       static_cast<uint64_t>(media_receiver_info.payload_bytes_rcvd);
274   inbound_stats->header_bytes_received =
275       static_cast<uint64_t>(media_receiver_info.header_and_padding_bytes_rcvd);
276   inbound_stats->packets_lost =
277       static_cast<int32_t>(media_receiver_info.packets_lost);
278 }
279 
SetInboundRTPStreamStatsFromVoiceReceiverInfo(const std::string & mid,const cricket::VoiceReceiverInfo & voice_receiver_info,RTCInboundRTPStreamStats * inbound_audio)280 void SetInboundRTPStreamStatsFromVoiceReceiverInfo(
281     const std::string& mid,
282     const cricket::VoiceReceiverInfo& voice_receiver_info,
283     RTCInboundRTPStreamStats* inbound_audio) {
284   SetInboundRTPStreamStatsFromMediaReceiverInfo(voice_receiver_info,
285                                                 inbound_audio);
286   inbound_audio->media_type = "audio";
287   inbound_audio->kind = "audio";
288   if (voice_receiver_info.codec_payload_type) {
289     inbound_audio->codec_id = RTCCodecStatsIDFromMidDirectionAndPayload(
290         mid, true, *voice_receiver_info.codec_payload_type);
291   }
292   inbound_audio->jitter = static_cast<double>(voice_receiver_info.jitter_ms) /
293                           rtc::kNumMillisecsPerSec;
294   inbound_audio->jitter_buffer_delay =
295       voice_receiver_info.jitter_buffer_delay_seconds;
296   inbound_audio->jitter_buffer_emitted_count =
297       voice_receiver_info.jitter_buffer_emitted_count;
298   inbound_audio->total_samples_received =
299       voice_receiver_info.total_samples_received;
300   inbound_audio->concealed_samples = voice_receiver_info.concealed_samples;
301   inbound_audio->silent_concealed_samples =
302       voice_receiver_info.silent_concealed_samples;
303   inbound_audio->concealment_events = voice_receiver_info.concealment_events;
304   inbound_audio->inserted_samples_for_deceleration =
305       voice_receiver_info.inserted_samples_for_deceleration;
306   inbound_audio->removed_samples_for_acceleration =
307       voice_receiver_info.removed_samples_for_acceleration;
308   inbound_audio->audio_level = voice_receiver_info.audio_level;
309   inbound_audio->total_audio_energy = voice_receiver_info.total_output_energy;
310   inbound_audio->total_samples_duration =
311       voice_receiver_info.total_output_duration;
312   // |fir_count|, |pli_count| and |sli_count| are only valid for video and are
313   // purposefully left undefined for audio.
314   if (voice_receiver_info.last_packet_received_timestamp_ms) {
315     inbound_audio->last_packet_received_timestamp =
316         static_cast<double>(
317             *voice_receiver_info.last_packet_received_timestamp_ms) /
318         rtc::kNumMillisecsPerSec;
319   }
320   if (voice_receiver_info.estimated_playout_ntp_timestamp_ms) {
321     inbound_audio->estimated_playout_timestamp = static_cast<double>(
322         *voice_receiver_info.estimated_playout_ntp_timestamp_ms);
323   }
324   inbound_audio->fec_packets_received =
325       voice_receiver_info.fec_packets_received;
326   inbound_audio->fec_packets_discarded =
327       voice_receiver_info.fec_packets_discarded;
328 }
329 
SetInboundRTPStreamStatsFromVideoReceiverInfo(const std::string & mid,const cricket::VideoReceiverInfo & video_receiver_info,RTCInboundRTPStreamStats * inbound_video)330 void SetInboundRTPStreamStatsFromVideoReceiverInfo(
331     const std::string& mid,
332     const cricket::VideoReceiverInfo& video_receiver_info,
333     RTCInboundRTPStreamStats* inbound_video) {
334   SetInboundRTPStreamStatsFromMediaReceiverInfo(video_receiver_info,
335                                                 inbound_video);
336   inbound_video->media_type = "video";
337   inbound_video->kind = "video";
338   if (video_receiver_info.codec_payload_type) {
339     inbound_video->codec_id = RTCCodecStatsIDFromMidDirectionAndPayload(
340         mid, true, *video_receiver_info.codec_payload_type);
341   }
342   inbound_video->fir_count =
343       static_cast<uint32_t>(video_receiver_info.firs_sent);
344   inbound_video->pli_count =
345       static_cast<uint32_t>(video_receiver_info.plis_sent);
346   inbound_video->nack_count =
347       static_cast<uint32_t>(video_receiver_info.nacks_sent);
348   inbound_video->frames_received = video_receiver_info.frames_received;
349   inbound_video->frames_decoded = video_receiver_info.frames_decoded;
350   inbound_video->frames_dropped = video_receiver_info.frames_dropped;
351   inbound_video->key_frames_decoded = video_receiver_info.key_frames_decoded;
352   if (video_receiver_info.frame_width > 0) {
353     inbound_video->frame_width =
354         static_cast<uint32_t>(video_receiver_info.frame_width);
355   }
356   if (video_receiver_info.frame_height > 0) {
357     inbound_video->frame_height =
358         static_cast<uint32_t>(video_receiver_info.frame_height);
359   }
360   if (video_receiver_info.framerate_rcvd > 0) {
361     inbound_video->frames_per_second = video_receiver_info.framerate_rcvd;
362   }
363   if (video_receiver_info.qp_sum)
364     inbound_video->qp_sum = *video_receiver_info.qp_sum;
365   inbound_video->total_decode_time =
366       static_cast<double>(video_receiver_info.total_decode_time_ms) /
367       rtc::kNumMillisecsPerSec;
368   inbound_video->total_inter_frame_delay =
369       video_receiver_info.total_inter_frame_delay;
370   inbound_video->total_squared_inter_frame_delay =
371       video_receiver_info.total_squared_inter_frame_delay;
372   if (video_receiver_info.last_packet_received_timestamp_ms) {
373     inbound_video->last_packet_received_timestamp =
374         static_cast<double>(
375             *video_receiver_info.last_packet_received_timestamp_ms) /
376         rtc::kNumMillisecsPerSec;
377   }
378   if (video_receiver_info.estimated_playout_ntp_timestamp_ms) {
379     inbound_video->estimated_playout_timestamp = static_cast<double>(
380         *video_receiver_info.estimated_playout_ntp_timestamp_ms);
381   }
382   // TODO(https://crbug.com/webrtc/10529): When info's |content_info| is
383   // optional, support the "unspecified" value.
384   if (video_receiver_info.content_type == VideoContentType::SCREENSHARE)
385     inbound_video->content_type = RTCContentType::kScreenshare;
386   if (!video_receiver_info.decoder_implementation_name.empty()) {
387     inbound_video->decoder_implementation =
388         video_receiver_info.decoder_implementation_name;
389   }
390 }
391 
392 // Provides the media independent counters (both audio and video).
SetOutboundRTPStreamStatsFromMediaSenderInfo(const cricket::MediaSenderInfo & media_sender_info,RTCOutboundRTPStreamStats * outbound_stats)393 void SetOutboundRTPStreamStatsFromMediaSenderInfo(
394     const cricket::MediaSenderInfo& media_sender_info,
395     RTCOutboundRTPStreamStats* outbound_stats) {
396   RTC_DCHECK(outbound_stats);
397   outbound_stats->ssrc = media_sender_info.ssrc();
398   // TODO(hbos): Support the remote case. https://crbug.com/657856
399   outbound_stats->is_remote = false;
400   outbound_stats->packets_sent =
401       static_cast<uint32_t>(media_sender_info.packets_sent);
402   outbound_stats->retransmitted_packets_sent =
403       media_sender_info.retransmitted_packets_sent;
404   outbound_stats->bytes_sent =
405       static_cast<uint64_t>(media_sender_info.payload_bytes_sent);
406   outbound_stats->header_bytes_sent =
407       static_cast<uint64_t>(media_sender_info.header_and_padding_bytes_sent);
408   outbound_stats->retransmitted_bytes_sent =
409       media_sender_info.retransmitted_bytes_sent;
410 }
411 
SetOutboundRTPStreamStatsFromVoiceSenderInfo(const std::string & mid,const cricket::VoiceSenderInfo & voice_sender_info,RTCOutboundRTPStreamStats * outbound_audio)412 void SetOutboundRTPStreamStatsFromVoiceSenderInfo(
413     const std::string& mid,
414     const cricket::VoiceSenderInfo& voice_sender_info,
415     RTCOutboundRTPStreamStats* outbound_audio) {
416   SetOutboundRTPStreamStatsFromMediaSenderInfo(voice_sender_info,
417                                                outbound_audio);
418   outbound_audio->media_type = "audio";
419   outbound_audio->kind = "audio";
420   if (voice_sender_info.codec_payload_type) {
421     outbound_audio->codec_id = RTCCodecStatsIDFromMidDirectionAndPayload(
422         mid, false, *voice_sender_info.codec_payload_type);
423   }
424   // |fir_count|, |pli_count| and |sli_count| are only valid for video and are
425   // purposefully left undefined for audio.
426 }
427 
SetOutboundRTPStreamStatsFromVideoSenderInfo(const std::string & mid,const cricket::VideoSenderInfo & video_sender_info,RTCOutboundRTPStreamStats * outbound_video)428 void SetOutboundRTPStreamStatsFromVideoSenderInfo(
429     const std::string& mid,
430     const cricket::VideoSenderInfo& video_sender_info,
431     RTCOutboundRTPStreamStats* outbound_video) {
432   SetOutboundRTPStreamStatsFromMediaSenderInfo(video_sender_info,
433                                                outbound_video);
434   outbound_video->media_type = "video";
435   outbound_video->kind = "video";
436   if (video_sender_info.codec_payload_type) {
437     outbound_video->codec_id = RTCCodecStatsIDFromMidDirectionAndPayload(
438         mid, false, *video_sender_info.codec_payload_type);
439   }
440   outbound_video->fir_count =
441       static_cast<uint32_t>(video_sender_info.firs_rcvd);
442   outbound_video->pli_count =
443       static_cast<uint32_t>(video_sender_info.plis_rcvd);
444   outbound_video->nack_count =
445       static_cast<uint32_t>(video_sender_info.nacks_rcvd);
446   if (video_sender_info.qp_sum)
447     outbound_video->qp_sum = *video_sender_info.qp_sum;
448   outbound_video->frames_encoded = video_sender_info.frames_encoded;
449   outbound_video->key_frames_encoded = video_sender_info.key_frames_encoded;
450   outbound_video->total_encode_time =
451       static_cast<double>(video_sender_info.total_encode_time_ms) /
452       rtc::kNumMillisecsPerSec;
453   outbound_video->total_encoded_bytes_target =
454       video_sender_info.total_encoded_bytes_target;
455   if (video_sender_info.send_frame_width > 0) {
456     outbound_video->frame_width =
457         static_cast<uint32_t>(video_sender_info.send_frame_width);
458   }
459   if (video_sender_info.send_frame_height > 0) {
460     outbound_video->frame_height =
461         static_cast<uint32_t>(video_sender_info.send_frame_height);
462   }
463   if (video_sender_info.framerate_sent > 0) {
464     outbound_video->frames_per_second = video_sender_info.framerate_sent;
465   }
466   outbound_video->frames_sent = video_sender_info.frames_sent;
467   outbound_video->huge_frames_sent = video_sender_info.huge_frames_sent;
468   outbound_video->total_packet_send_delay =
469       static_cast<double>(video_sender_info.total_packet_send_delay_ms) /
470       rtc::kNumMillisecsPerSec;
471   outbound_video->quality_limitation_reason =
472       QualityLimitationReasonToRTCQualityLimitationReason(
473           video_sender_info.quality_limitation_reason);
474   outbound_video->quality_limitation_resolution_changes =
475       video_sender_info.quality_limitation_resolution_changes;
476   // TODO(https://crbug.com/webrtc/10529): When info's |content_info| is
477   // optional, support the "unspecified" value.
478   if (video_sender_info.content_type == VideoContentType::SCREENSHARE)
479     outbound_video->content_type = RTCContentType::kScreenshare;
480   if (!video_sender_info.encoder_implementation_name.empty()) {
481     outbound_video->encoder_implementation =
482         video_sender_info.encoder_implementation_name;
483   }
484   if (video_sender_info.rid) {
485     outbound_video->rid = *video_sender_info.rid;
486   }
487 }
488 
489 std::unique_ptr<RTCRemoteInboundRtpStreamStats>
ProduceRemoteInboundRtpStreamStatsFromReportBlockData(const ReportBlockData & report_block_data,cricket::MediaType media_type,const std::map<std::string,RTCOutboundRTPStreamStats * > & outbound_rtps,const RTCStatsReport & report)490 ProduceRemoteInboundRtpStreamStatsFromReportBlockData(
491     const ReportBlockData& report_block_data,
492     cricket::MediaType media_type,
493     const std::map<std::string, RTCOutboundRTPStreamStats*>& outbound_rtps,
494     const RTCStatsReport& report) {
495   const auto& report_block = report_block_data.report_block();
496   // RTCStats' timestamp generally refers to when the metric was sampled, but
497   // for "remote-[outbound/inbound]-rtp" it refers to the local time when the
498   // Report Block was received.
499   auto remote_inbound = std::make_unique<RTCRemoteInboundRtpStreamStats>(
500       RTCRemoteInboundRtpStreamStatsIdFromSourceSsrc(media_type,
501                                                      report_block.source_ssrc),
502       /*timestamp=*/report_block_data.report_block_timestamp_utc_us());
503   remote_inbound->ssrc = report_block.source_ssrc;
504   remote_inbound->kind =
505       media_type == cricket::MEDIA_TYPE_AUDIO ? "audio" : "video";
506   remote_inbound->packets_lost = report_block.packets_lost;
507   remote_inbound->round_trip_time =
508       static_cast<double>(report_block_data.last_rtt_ms()) /
509       rtc::kNumMillisecsPerSec;
510 
511   std::string local_id = RTCOutboundRTPStreamStatsIDFromSSRC(
512       media_type == cricket::MEDIA_TYPE_AUDIO, report_block.source_ssrc);
513   // Look up local stat from |outbound_rtps| where the pointers are non-const.
514   auto local_id_it = outbound_rtps.find(local_id);
515   if (local_id_it != outbound_rtps.end()) {
516     remote_inbound->local_id = local_id;
517     auto& outbound_rtp = *local_id_it->second;
518     outbound_rtp.remote_id = remote_inbound->id();
519     // The RTP/RTCP transport is obtained from the
520     // RTCOutboundRtpStreamStats's transport.
521     const auto* transport_from_id = outbound_rtp.transport_id.is_defined()
522                                         ? report.Get(*outbound_rtp.transport_id)
523                                         : nullptr;
524     if (transport_from_id) {
525       const auto& transport = transport_from_id->cast_to<RTCTransportStats>();
526       // If RTP and RTCP are not multiplexed, there is a separate RTCP
527       // transport paired with the RTP transport, otherwise the same
528       // transport is used for RTCP and RTP.
529       remote_inbound->transport_id =
530           transport.rtcp_transport_stats_id.is_defined()
531               ? *transport.rtcp_transport_stats_id
532               : *outbound_rtp.transport_id;
533     }
534     // We're assuming the same codec is used on both ends. However if the
535     // codec is switched out on the fly we may have received a Report Block
536     // based on the previous codec and there is no way to tell which point in
537     // time the codec changed for the remote end.
538     const auto* codec_from_id = outbound_rtp.codec_id.is_defined()
539                                     ? report.Get(*outbound_rtp.codec_id)
540                                     : nullptr;
541     if (codec_from_id) {
542       remote_inbound->codec_id = *outbound_rtp.codec_id;
543       const auto& codec = codec_from_id->cast_to<RTCCodecStats>();
544       if (codec.clock_rate.is_defined()) {
545         // The Report Block jitter is expressed in RTP timestamp units
546         // (https://tools.ietf.org/html/rfc3550#section-6.4.1). To convert this
547         // to seconds we divide by the codec's clock rate.
548         remote_inbound->jitter =
549             static_cast<double>(report_block.jitter) / *codec.clock_rate;
550       }
551     }
552   }
553   return remote_inbound;
554 }
555 
ProduceCertificateStatsFromSSLCertificateStats(int64_t timestamp_us,const rtc::SSLCertificateStats & certificate_stats,RTCStatsReport * report)556 void ProduceCertificateStatsFromSSLCertificateStats(
557     int64_t timestamp_us,
558     const rtc::SSLCertificateStats& certificate_stats,
559     RTCStatsReport* report) {
560   RTCCertificateStats* prev_certificate_stats = nullptr;
561   for (const rtc::SSLCertificateStats* s = &certificate_stats; s;
562        s = s->issuer.get()) {
563     std::string certificate_stats_id =
564         RTCCertificateIDFromFingerprint(s->fingerprint);
565     // It is possible for the same certificate to show up multiple times, e.g.
566     // if local and remote side use the same certificate in a loopback call.
567     // If the report already contains stats for this certificate, skip it.
568     if (report->Get(certificate_stats_id)) {
569       RTC_DCHECK_EQ(s, &certificate_stats);
570       break;
571     }
572     RTCCertificateStats* certificate_stats =
573         new RTCCertificateStats(certificate_stats_id, timestamp_us);
574     certificate_stats->fingerprint = s->fingerprint;
575     certificate_stats->fingerprint_algorithm = s->fingerprint_algorithm;
576     certificate_stats->base64_certificate = s->base64_certificate;
577     if (prev_certificate_stats)
578       prev_certificate_stats->issuer_certificate_id = certificate_stats->id();
579     report->AddStats(std::unique_ptr<RTCCertificateStats>(certificate_stats));
580     prev_certificate_stats = certificate_stats;
581   }
582 }
583 
ProduceIceCandidateStats(int64_t timestamp_us,const cricket::Candidate & candidate,bool is_local,const std::string & transport_id,RTCStatsReport * report)584 const std::string& ProduceIceCandidateStats(int64_t timestamp_us,
585                                             const cricket::Candidate& candidate,
586                                             bool is_local,
587                                             const std::string& transport_id,
588                                             RTCStatsReport* report) {
589   const std::string& id = "RTCIceCandidate_" + candidate.id();
590   const RTCStats* stats = report->Get(id);
591   if (!stats) {
592     std::unique_ptr<RTCIceCandidateStats> candidate_stats;
593     if (is_local)
594       candidate_stats.reset(new RTCLocalIceCandidateStats(id, timestamp_us));
595     else
596       candidate_stats.reset(new RTCRemoteIceCandidateStats(id, timestamp_us));
597     candidate_stats->transport_id = transport_id;
598     if (is_local) {
599       candidate_stats->network_type =
600           NetworkAdapterTypeToStatsType(candidate.network_type());
601       if (candidate.type() == cricket::RELAY_PORT_TYPE) {
602         std::string relay_protocol = candidate.relay_protocol();
603         RTC_DCHECK(relay_protocol.compare("udp") == 0 ||
604                    relay_protocol.compare("tcp") == 0 ||
605                    relay_protocol.compare("tls") == 0);
606         candidate_stats->relay_protocol = relay_protocol;
607       }
608     } else {
609       // We don't expect to know the adapter type of remote candidates.
610       RTC_DCHECK_EQ(rtc::ADAPTER_TYPE_UNKNOWN, candidate.network_type());
611     }
612     candidate_stats->ip = candidate.address().ipaddr().ToString();
613     candidate_stats->port = static_cast<int32_t>(candidate.address().port());
614     candidate_stats->protocol = candidate.protocol();
615     candidate_stats->candidate_type =
616         CandidateTypeToRTCIceCandidateType(candidate.type());
617     candidate_stats->priority = static_cast<int32_t>(candidate.priority());
618 
619     stats = candidate_stats.get();
620     report->AddStats(std::move(candidate_stats));
621   }
622   RTC_DCHECK_EQ(stats->type(), is_local ? RTCLocalIceCandidateStats::kType
623                                         : RTCRemoteIceCandidateStats::kType);
624   return stats->id();
625 }
626 
627 std::unique_ptr<RTCMediaStreamTrackStats>
ProduceMediaStreamTrackStatsFromVoiceSenderInfo(int64_t timestamp_us,const AudioTrackInterface & audio_track,const cricket::VoiceSenderInfo & voice_sender_info,int attachment_id)628 ProduceMediaStreamTrackStatsFromVoiceSenderInfo(
629     int64_t timestamp_us,
630     const AudioTrackInterface& audio_track,
631     const cricket::VoiceSenderInfo& voice_sender_info,
632     int attachment_id) {
633   std::unique_ptr<RTCMediaStreamTrackStats> audio_track_stats(
634       new RTCMediaStreamTrackStats(
635           RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(kSender,
636                                                                attachment_id),
637           timestamp_us, RTCMediaStreamTrackKind::kAudio));
638   SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
639       audio_track, audio_track_stats.get());
640   audio_track_stats->media_source_id =
641       RTCMediaSourceStatsIDFromKindAndAttachment(cricket::MEDIA_TYPE_AUDIO,
642                                                  attachment_id);
643   audio_track_stats->remote_source = false;
644   audio_track_stats->detached = false;
645   if (voice_sender_info.apm_statistics.echo_return_loss) {
646     audio_track_stats->echo_return_loss =
647         *voice_sender_info.apm_statistics.echo_return_loss;
648   }
649   if (voice_sender_info.apm_statistics.echo_return_loss_enhancement) {
650     audio_track_stats->echo_return_loss_enhancement =
651         *voice_sender_info.apm_statistics.echo_return_loss_enhancement;
652   }
653   return audio_track_stats;
654 }
655 
656 std::unique_ptr<RTCMediaStreamTrackStats>
ProduceMediaStreamTrackStatsFromVoiceReceiverInfo(int64_t timestamp_us,const AudioTrackInterface & audio_track,const cricket::VoiceReceiverInfo & voice_receiver_info,int attachment_id)657 ProduceMediaStreamTrackStatsFromVoiceReceiverInfo(
658     int64_t timestamp_us,
659     const AudioTrackInterface& audio_track,
660     const cricket::VoiceReceiverInfo& voice_receiver_info,
661     int attachment_id) {
662   // Since receiver tracks can't be reattached, we use the SSRC as
663   // an attachment identifier.
664   std::unique_ptr<RTCMediaStreamTrackStats> audio_track_stats(
665       new RTCMediaStreamTrackStats(
666           RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(kReceiver,
667                                                                attachment_id),
668           timestamp_us, RTCMediaStreamTrackKind::kAudio));
669   SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
670       audio_track, audio_track_stats.get());
671   audio_track_stats->remote_source = true;
672   audio_track_stats->detached = false;
673   if (voice_receiver_info.audio_level >= 0) {
674     audio_track_stats->audio_level =
675         DoubleAudioLevelFromIntAudioLevel(voice_receiver_info.audio_level);
676   }
677   audio_track_stats->jitter_buffer_delay =
678       voice_receiver_info.jitter_buffer_delay_seconds;
679   audio_track_stats->jitter_buffer_emitted_count =
680       voice_receiver_info.jitter_buffer_emitted_count;
681   audio_track_stats->inserted_samples_for_deceleration =
682       voice_receiver_info.inserted_samples_for_deceleration;
683   audio_track_stats->removed_samples_for_acceleration =
684       voice_receiver_info.removed_samples_for_acceleration;
685   audio_track_stats->total_audio_energy =
686       voice_receiver_info.total_output_energy;
687   audio_track_stats->total_samples_received =
688       voice_receiver_info.total_samples_received;
689   audio_track_stats->total_samples_duration =
690       voice_receiver_info.total_output_duration;
691   audio_track_stats->concealed_samples = voice_receiver_info.concealed_samples;
692   audio_track_stats->silent_concealed_samples =
693       voice_receiver_info.silent_concealed_samples;
694   audio_track_stats->concealment_events =
695       voice_receiver_info.concealment_events;
696   audio_track_stats->jitter_buffer_flushes =
697       voice_receiver_info.jitter_buffer_flushes;
698   audio_track_stats->delayed_packet_outage_samples =
699       voice_receiver_info.delayed_packet_outage_samples;
700   audio_track_stats->relative_packet_arrival_delay =
701       voice_receiver_info.relative_packet_arrival_delay_seconds;
702   audio_track_stats->jitter_buffer_target_delay =
703       voice_receiver_info.jitter_buffer_target_delay_seconds;
704   audio_track_stats->interruption_count =
705       voice_receiver_info.interruption_count >= 0
706           ? voice_receiver_info.interruption_count
707           : 0;
708   audio_track_stats->total_interruption_duration =
709       static_cast<double>(voice_receiver_info.total_interruption_duration_ms) /
710       rtc::kNumMillisecsPerSec;
711   return audio_track_stats;
712 }
713 
714 std::unique_ptr<RTCMediaStreamTrackStats>
ProduceMediaStreamTrackStatsFromVideoSenderInfo(int64_t timestamp_us,const VideoTrackInterface & video_track,const cricket::VideoSenderInfo & video_sender_info,int attachment_id)715 ProduceMediaStreamTrackStatsFromVideoSenderInfo(
716     int64_t timestamp_us,
717     const VideoTrackInterface& video_track,
718     const cricket::VideoSenderInfo& video_sender_info,
719     int attachment_id) {
720   std::unique_ptr<RTCMediaStreamTrackStats> video_track_stats(
721       new RTCMediaStreamTrackStats(
722           RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(kSender,
723                                                                attachment_id),
724           timestamp_us, RTCMediaStreamTrackKind::kVideo));
725   SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
726       video_track, video_track_stats.get());
727   video_track_stats->media_source_id =
728       RTCMediaSourceStatsIDFromKindAndAttachment(cricket::MEDIA_TYPE_VIDEO,
729                                                  attachment_id);
730   video_track_stats->remote_source = false;
731   video_track_stats->detached = false;
732   video_track_stats->frame_width =
733       static_cast<uint32_t>(video_sender_info.send_frame_width);
734   video_track_stats->frame_height =
735       static_cast<uint32_t>(video_sender_info.send_frame_height);
736   // TODO(hbos): Will reduce this by frames dropped due to congestion control
737   // when available. https://crbug.com/659137
738   video_track_stats->frames_sent = video_sender_info.frames_encoded;
739   video_track_stats->huge_frames_sent = video_sender_info.huge_frames_sent;
740   return video_track_stats;
741 }
742 
743 std::unique_ptr<RTCMediaStreamTrackStats>
ProduceMediaStreamTrackStatsFromVideoReceiverInfo(int64_t timestamp_us,const VideoTrackInterface & video_track,const cricket::VideoReceiverInfo & video_receiver_info,int attachment_id)744 ProduceMediaStreamTrackStatsFromVideoReceiverInfo(
745     int64_t timestamp_us,
746     const VideoTrackInterface& video_track,
747     const cricket::VideoReceiverInfo& video_receiver_info,
748     int attachment_id) {
749   std::unique_ptr<RTCMediaStreamTrackStats> video_track_stats(
750       new RTCMediaStreamTrackStats(
751           RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(kReceiver,
752 
753                                                                attachment_id),
754           timestamp_us, RTCMediaStreamTrackKind::kVideo));
755   SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
756       video_track, video_track_stats.get());
757   video_track_stats->remote_source = true;
758   video_track_stats->detached = false;
759   if (video_receiver_info.frame_width > 0 &&
760       video_receiver_info.frame_height > 0) {
761     video_track_stats->frame_width =
762         static_cast<uint32_t>(video_receiver_info.frame_width);
763     video_track_stats->frame_height =
764         static_cast<uint32_t>(video_receiver_info.frame_height);
765   }
766   video_track_stats->jitter_buffer_delay =
767       video_receiver_info.jitter_buffer_delay_seconds;
768   video_track_stats->jitter_buffer_emitted_count =
769       video_receiver_info.jitter_buffer_emitted_count;
770   video_track_stats->frames_received = video_receiver_info.frames_received;
771   // TODO(hbos): When we support receiving simulcast, this should be the total
772   // number of frames correctly decoded, independent of which SSRC it was
773   // received from. Since we don't support that, this is correct and is the same
774   // value as "RTCInboundRTPStreamStats.framesDecoded". https://crbug.com/659137
775   video_track_stats->frames_decoded = video_receiver_info.frames_decoded;
776   video_track_stats->frames_dropped = video_receiver_info.frames_dropped;
777   video_track_stats->freeze_count = video_receiver_info.freeze_count;
778   video_track_stats->pause_count = video_receiver_info.pause_count;
779   video_track_stats->total_freezes_duration =
780       static_cast<double>(video_receiver_info.total_freezes_duration_ms) /
781       rtc::kNumMillisecsPerSec;
782   video_track_stats->total_pauses_duration =
783       static_cast<double>(video_receiver_info.total_pauses_duration_ms) /
784       rtc::kNumMillisecsPerSec;
785   video_track_stats->total_frames_duration =
786       static_cast<double>(video_receiver_info.total_frames_duration_ms) /
787       rtc::kNumMillisecsPerSec;
788   video_track_stats->sum_squared_frame_durations =
789       video_receiver_info.sum_squared_frame_durations;
790 
791   return video_track_stats;
792 }
793 
ProduceSenderMediaTrackStats(int64_t timestamp_us,const TrackMediaInfoMap & track_media_info_map,std::vector<rtc::scoped_refptr<RtpSenderInternal>> senders,RTCStatsReport * report)794 void ProduceSenderMediaTrackStats(
795     int64_t timestamp_us,
796     const TrackMediaInfoMap& track_media_info_map,
797     std::vector<rtc::scoped_refptr<RtpSenderInternal>> senders,
798     RTCStatsReport* report) {
799   // This function iterates over the senders to generate outgoing track stats.
800 
801   // TODO(hbos): Return stats of detached tracks. We have to perform stats
802   // gathering at the time of detachment to get accurate stats and timestamps.
803   // https://crbug.com/659137
804   for (const auto& sender : senders) {
805     if (sender->media_type() == cricket::MEDIA_TYPE_AUDIO) {
806       AudioTrackInterface* track =
807           static_cast<AudioTrackInterface*>(sender->track().get());
808       if (!track)
809         continue;
810       cricket::VoiceSenderInfo null_sender_info;
811       const cricket::VoiceSenderInfo* voice_sender_info = &null_sender_info;
812       // TODO(hta): Checking on ssrc is not proper. There should be a way
813       // to see from a sender whether it's connected or not.
814       // Related to https://crbug.com/8694 (using ssrc 0 to indicate "none")
815       if (sender->ssrc() != 0) {
816         // When pc.close is called, sender info is discarded, so
817         // we generate zeroes instead. Bug: It should be retained.
818         // https://crbug.com/807174
819         const cricket::VoiceSenderInfo* sender_info =
820             track_media_info_map.GetVoiceSenderInfoBySsrc(sender->ssrc());
821         if (sender_info) {
822           voice_sender_info = sender_info;
823         } else {
824           RTC_LOG(LS_INFO)
825               << "RTCStatsCollector: No voice sender info for sender with ssrc "
826               << sender->ssrc();
827         }
828       }
829       std::unique_ptr<RTCMediaStreamTrackStats> audio_track_stats =
830           ProduceMediaStreamTrackStatsFromVoiceSenderInfo(
831               timestamp_us, *track, *voice_sender_info, sender->AttachmentId());
832       report->AddStats(std::move(audio_track_stats));
833     } else if (sender->media_type() == cricket::MEDIA_TYPE_VIDEO) {
834       VideoTrackInterface* track =
835           static_cast<VideoTrackInterface*>(sender->track().get());
836       if (!track)
837         continue;
838       cricket::VideoSenderInfo null_sender_info;
839       const cricket::VideoSenderInfo* video_sender_info = &null_sender_info;
840       // TODO(hta): Check on state not ssrc when state is available
841       // Related to https://bugs.webrtc.org/8694 (using ssrc 0 to indicate
842       // "none")
843       if (sender->ssrc() != 0) {
844         // When pc.close is called, sender info is discarded, so
845         // we generate zeroes instead. Bug: It should be retained.
846         // https://crbug.com/807174
847         const cricket::VideoSenderInfo* sender_info =
848             track_media_info_map.GetVideoSenderInfoBySsrc(sender->ssrc());
849         if (sender_info) {
850           video_sender_info = sender_info;
851         } else {
852           RTC_LOG(LS_INFO) << "No video sender info for sender with ssrc "
853                            << sender->ssrc();
854         }
855       }
856       std::unique_ptr<RTCMediaStreamTrackStats> video_track_stats =
857           ProduceMediaStreamTrackStatsFromVideoSenderInfo(
858               timestamp_us, *track, *video_sender_info, sender->AttachmentId());
859       report->AddStats(std::move(video_track_stats));
860     } else {
861       RTC_NOTREACHED();
862     }
863   }
864 }
865 
ProduceReceiverMediaTrackStats(int64_t timestamp_us,const TrackMediaInfoMap & track_media_info_map,std::vector<rtc::scoped_refptr<RtpReceiverInternal>> receivers,RTCStatsReport * report)866 void ProduceReceiverMediaTrackStats(
867     int64_t timestamp_us,
868     const TrackMediaInfoMap& track_media_info_map,
869     std::vector<rtc::scoped_refptr<RtpReceiverInternal>> receivers,
870     RTCStatsReport* report) {
871   // This function iterates over the receivers to find the remote tracks.
872   for (const auto& receiver : receivers) {
873     if (receiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
874       AudioTrackInterface* track =
875           static_cast<AudioTrackInterface*>(receiver->track().get());
876       const cricket::VoiceReceiverInfo* voice_receiver_info =
877           track_media_info_map.GetVoiceReceiverInfo(*track);
878       if (!voice_receiver_info) {
879         continue;
880       }
881       std::unique_ptr<RTCMediaStreamTrackStats> audio_track_stats =
882           ProduceMediaStreamTrackStatsFromVoiceReceiverInfo(
883               timestamp_us, *track, *voice_receiver_info,
884               receiver->AttachmentId());
885       report->AddStats(std::move(audio_track_stats));
886     } else if (receiver->media_type() == cricket::MEDIA_TYPE_VIDEO) {
887       VideoTrackInterface* track =
888           static_cast<VideoTrackInterface*>(receiver->track().get());
889       const cricket::VideoReceiverInfo* video_receiver_info =
890           track_media_info_map.GetVideoReceiverInfo(*track);
891       if (!video_receiver_info) {
892         continue;
893       }
894       std::unique_ptr<RTCMediaStreamTrackStats> video_track_stats =
895           ProduceMediaStreamTrackStatsFromVideoReceiverInfo(
896               timestamp_us, *track, *video_receiver_info,
897               receiver->AttachmentId());
898       report->AddStats(std::move(video_track_stats));
899     } else {
900       RTC_NOTREACHED();
901     }
902   }
903 }
904 
CreateReportFilteredBySelector(bool filter_by_sender_selector,rtc::scoped_refptr<const RTCStatsReport> report,rtc::scoped_refptr<RtpSenderInternal> sender_selector,rtc::scoped_refptr<RtpReceiverInternal> receiver_selector)905 rtc::scoped_refptr<RTCStatsReport> CreateReportFilteredBySelector(
906     bool filter_by_sender_selector,
907     rtc::scoped_refptr<const RTCStatsReport> report,
908     rtc::scoped_refptr<RtpSenderInternal> sender_selector,
909     rtc::scoped_refptr<RtpReceiverInternal> receiver_selector) {
910   std::vector<std::string> rtpstream_ids;
911   if (filter_by_sender_selector) {
912     // Filter mode: RTCStatsCollector::RequestInfo::kSenderSelector
913     if (sender_selector) {
914       // Find outbound-rtp(s) of the sender, i.e. the outbound-rtp(s) that
915       // reference the sender stats.
916       // Because we do not implement sender stats, we look at outbound-rtp(s)
917       // that reference the track attachment stats for the sender instead.
918       std::string track_id =
919           RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
920               kSender, sender_selector->AttachmentId());
921       for (const auto& stats : *report) {
922         if (stats.type() != RTCOutboundRTPStreamStats::kType)
923           continue;
924         const auto& outbound_rtp = stats.cast_to<RTCOutboundRTPStreamStats>();
925         if (outbound_rtp.track_id.is_defined() &&
926             *outbound_rtp.track_id == track_id) {
927           rtpstream_ids.push_back(outbound_rtp.id());
928         }
929       }
930     }
931   } else {
932     // Filter mode: RTCStatsCollector::RequestInfo::kReceiverSelector
933     if (receiver_selector) {
934       // Find inbound-rtp(s) of the receiver, i.e. the inbound-rtp(s) that
935       // reference the receiver stats.
936       // Because we do not implement receiver stats, we look at inbound-rtp(s)
937       // that reference the track attachment stats for the receiver instead.
938       std::string track_id =
939           RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
940               kReceiver, receiver_selector->AttachmentId());
941       for (const auto& stats : *report) {
942         if (stats.type() != RTCInboundRTPStreamStats::kType)
943           continue;
944         const auto& inbound_rtp = stats.cast_to<RTCInboundRTPStreamStats>();
945         if (inbound_rtp.track_id.is_defined() &&
946             *inbound_rtp.track_id == track_id) {
947           rtpstream_ids.push_back(inbound_rtp.id());
948         }
949       }
950     }
951   }
952   if (rtpstream_ids.empty())
953     return RTCStatsReport::Create(report->timestamp_us());
954   return TakeReferencedStats(report->Copy(), rtpstream_ids);
955 }
956 
957 }  // namespace
958 
RequestInfo(rtc::scoped_refptr<RTCStatsCollectorCallback> callback)959 RTCStatsCollector::RequestInfo::RequestInfo(
960     rtc::scoped_refptr<RTCStatsCollectorCallback> callback)
961     : RequestInfo(FilterMode::kAll, std::move(callback), nullptr, nullptr) {}
962 
RequestInfo(rtc::scoped_refptr<RtpSenderInternal> selector,rtc::scoped_refptr<RTCStatsCollectorCallback> callback)963 RTCStatsCollector::RequestInfo::RequestInfo(
964     rtc::scoped_refptr<RtpSenderInternal> selector,
965     rtc::scoped_refptr<RTCStatsCollectorCallback> callback)
966     : RequestInfo(FilterMode::kSenderSelector,
967                   std::move(callback),
968                   std::move(selector),
969                   nullptr) {}
970 
RequestInfo(rtc::scoped_refptr<RtpReceiverInternal> selector,rtc::scoped_refptr<RTCStatsCollectorCallback> callback)971 RTCStatsCollector::RequestInfo::RequestInfo(
972     rtc::scoped_refptr<RtpReceiverInternal> selector,
973     rtc::scoped_refptr<RTCStatsCollectorCallback> callback)
974     : RequestInfo(FilterMode::kReceiverSelector,
975                   std::move(callback),
976                   nullptr,
977                   std::move(selector)) {}
978 
RequestInfo(RTCStatsCollector::RequestInfo::FilterMode filter_mode,rtc::scoped_refptr<RTCStatsCollectorCallback> callback,rtc::scoped_refptr<RtpSenderInternal> sender_selector,rtc::scoped_refptr<RtpReceiverInternal> receiver_selector)979 RTCStatsCollector::RequestInfo::RequestInfo(
980     RTCStatsCollector::RequestInfo::FilterMode filter_mode,
981     rtc::scoped_refptr<RTCStatsCollectorCallback> callback,
982     rtc::scoped_refptr<RtpSenderInternal> sender_selector,
983     rtc::scoped_refptr<RtpReceiverInternal> receiver_selector)
984     : filter_mode_(filter_mode),
985       callback_(std::move(callback)),
986       sender_selector_(std::move(sender_selector)),
987       receiver_selector_(std::move(receiver_selector)) {
988   RTC_DCHECK(callback_);
989   RTC_DCHECK(!sender_selector_ || !receiver_selector_);
990 }
991 
Create(PeerConnectionInternal * pc,int64_t cache_lifetime_us)992 rtc::scoped_refptr<RTCStatsCollector> RTCStatsCollector::Create(
993     PeerConnectionInternal* pc,
994     int64_t cache_lifetime_us) {
995   return rtc::scoped_refptr<RTCStatsCollector>(
996       new rtc::RefCountedObject<RTCStatsCollector>(pc, cache_lifetime_us));
997 }
998 
RTCStatsCollector(PeerConnectionInternal * pc,int64_t cache_lifetime_us)999 RTCStatsCollector::RTCStatsCollector(PeerConnectionInternal* pc,
1000                                      int64_t cache_lifetime_us)
1001     : pc_(pc),
1002       signaling_thread_(pc->signaling_thread()),
1003       worker_thread_(pc->worker_thread()),
1004       network_thread_(pc->network_thread()),
1005       num_pending_partial_reports_(0),
1006       partial_report_timestamp_us_(0),
1007       network_report_event_(true /* manual_reset */,
1008                             true /* initially_signaled */),
1009       cache_timestamp_us_(0),
1010       cache_lifetime_us_(cache_lifetime_us) {
1011   RTC_DCHECK(pc_);
1012   RTC_DCHECK(signaling_thread_);
1013   RTC_DCHECK(worker_thread_);
1014   RTC_DCHECK(network_thread_);
1015   RTC_DCHECK_GE(cache_lifetime_us_, 0);
1016   pc_->SignalRtpDataChannelCreated().connect(
1017       this, &RTCStatsCollector::OnRtpDataChannelCreated);
1018   pc_->SignalSctpDataChannelCreated().connect(
1019       this, &RTCStatsCollector::OnSctpDataChannelCreated);
1020 }
1021 
~RTCStatsCollector()1022 RTCStatsCollector::~RTCStatsCollector() {
1023   RTC_DCHECK_EQ(num_pending_partial_reports_, 0);
1024 }
1025 
GetStatsReport(rtc::scoped_refptr<RTCStatsCollectorCallback> callback)1026 void RTCStatsCollector::GetStatsReport(
1027     rtc::scoped_refptr<RTCStatsCollectorCallback> callback) {
1028   GetStatsReportInternal(RequestInfo(std::move(callback)));
1029 }
1030 
GetStatsReport(rtc::scoped_refptr<RtpSenderInternal> selector,rtc::scoped_refptr<RTCStatsCollectorCallback> callback)1031 void RTCStatsCollector::GetStatsReport(
1032     rtc::scoped_refptr<RtpSenderInternal> selector,
1033     rtc::scoped_refptr<RTCStatsCollectorCallback> callback) {
1034   GetStatsReportInternal(RequestInfo(std::move(selector), std::move(callback)));
1035 }
1036 
GetStatsReport(rtc::scoped_refptr<RtpReceiverInternal> selector,rtc::scoped_refptr<RTCStatsCollectorCallback> callback)1037 void RTCStatsCollector::GetStatsReport(
1038     rtc::scoped_refptr<RtpReceiverInternal> selector,
1039     rtc::scoped_refptr<RTCStatsCollectorCallback> callback) {
1040   GetStatsReportInternal(RequestInfo(std::move(selector), std::move(callback)));
1041 }
1042 
GetStatsReportInternal(RTCStatsCollector::RequestInfo request)1043 void RTCStatsCollector::GetStatsReportInternal(
1044     RTCStatsCollector::RequestInfo request) {
1045   RTC_DCHECK(signaling_thread_->IsCurrent());
1046   requests_.push_back(std::move(request));
1047 
1048   // "Now" using a monotonically increasing timer.
1049   int64_t cache_now_us = rtc::TimeMicros();
1050   if (cached_report_ &&
1051       cache_now_us - cache_timestamp_us_ <= cache_lifetime_us_) {
1052     // We have a fresh cached report to deliver. Deliver asynchronously, since
1053     // the caller may not be expecting a synchronous callback, and it avoids
1054     // reentrancy problems.
1055     std::vector<RequestInfo> requests;
1056     requests.swap(requests_);
1057     signaling_thread_->PostTask(
1058         RTC_FROM_HERE, rtc::Bind(&RTCStatsCollector::DeliverCachedReport, this,
1059                                  cached_report_, std::move(requests)));
1060   } else if (!num_pending_partial_reports_) {
1061     // Only start gathering stats if we're not already gathering stats. In the
1062     // case of already gathering stats, |callback_| will be invoked when there
1063     // are no more pending partial reports.
1064 
1065     // "Now" using a system clock, relative to the UNIX epoch (Jan 1, 1970,
1066     // UTC), in microseconds. The system clock could be modified and is not
1067     // necessarily monotonically increasing.
1068     int64_t timestamp_us = rtc::TimeUTCMicros();
1069 
1070     num_pending_partial_reports_ = 2;
1071     partial_report_timestamp_us_ = cache_now_us;
1072 
1073     // Prepare |transceiver_stats_infos_| for use in
1074     // |ProducePartialResultsOnNetworkThread| and
1075     // |ProducePartialResultsOnSignalingThread|.
1076     transceiver_stats_infos_ = PrepareTransceiverStatsInfos_s_w();
1077     // Prepare |transport_names_| for use in
1078     // |ProducePartialResultsOnNetworkThread|.
1079     transport_names_ = PrepareTransportNames_s();
1080 
1081     // Prepare |call_stats_| here since GetCallStats() will hop to the worker
1082     // thread.
1083     // TODO(holmer): To avoid the hop we could move BWE and BWE stats to the
1084     // network thread, where it more naturally belongs.
1085     // TODO(https://crbug.com/webrtc/11767): In the meantime we can piggyback on
1086     // the blocking-invoke that is already performed in
1087     // PrepareTransceiverStatsInfos_s_w() so that we can call GetCallStats()
1088     // without additional blocking-invokes.
1089     call_stats_ = pc_->GetCallStats();
1090 
1091     // Don't touch |network_report_| on the signaling thread until
1092     // ProducePartialResultsOnNetworkThread() has signaled the
1093     // |network_report_event_|.
1094     network_report_event_.Reset();
1095     network_thread_->PostTask(
1096         RTC_FROM_HERE,
1097         rtc::Bind(&RTCStatsCollector::ProducePartialResultsOnNetworkThread,
1098                   this, timestamp_us));
1099     ProducePartialResultsOnSignalingThread(timestamp_us);
1100   }
1101 }
1102 
ClearCachedStatsReport()1103 void RTCStatsCollector::ClearCachedStatsReport() {
1104   RTC_DCHECK(signaling_thread_->IsCurrent());
1105   cached_report_ = nullptr;
1106 }
1107 
WaitForPendingRequest()1108 void RTCStatsCollector::WaitForPendingRequest() {
1109   RTC_DCHECK(signaling_thread_->IsCurrent());
1110   // If a request is pending, blocks until the |network_report_event_| is
1111   // signaled and then delivers the result. Otherwise this is a NO-OP.
1112   MergeNetworkReport_s();
1113 }
1114 
ProducePartialResultsOnSignalingThread(int64_t timestamp_us)1115 void RTCStatsCollector::ProducePartialResultsOnSignalingThread(
1116     int64_t timestamp_us) {
1117   RTC_DCHECK(signaling_thread_->IsCurrent());
1118   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1119 
1120   partial_report_ = RTCStatsReport::Create(timestamp_us);
1121 
1122   ProducePartialResultsOnSignalingThreadImpl(timestamp_us,
1123                                              partial_report_.get());
1124 
1125   // ProducePartialResultsOnSignalingThread() is running synchronously on the
1126   // signaling thread, so it is always the first partial result delivered on the
1127   // signaling thread. The request is not complete until MergeNetworkReport_s()
1128   // happens; we don't have to do anything here.
1129   RTC_DCHECK_GT(num_pending_partial_reports_, 1);
1130   --num_pending_partial_reports_;
1131 }
1132 
ProducePartialResultsOnSignalingThreadImpl(int64_t timestamp_us,RTCStatsReport * partial_report)1133 void RTCStatsCollector::ProducePartialResultsOnSignalingThreadImpl(
1134     int64_t timestamp_us,
1135     RTCStatsReport* partial_report) {
1136   RTC_DCHECK(signaling_thread_->IsCurrent());
1137   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1138 
1139   ProduceDataChannelStats_s(timestamp_us, partial_report);
1140   ProduceMediaStreamStats_s(timestamp_us, partial_report);
1141   ProduceMediaStreamTrackStats_s(timestamp_us, partial_report);
1142   ProduceMediaSourceStats_s(timestamp_us, partial_report);
1143   ProducePeerConnectionStats_s(timestamp_us, partial_report);
1144 }
1145 
ProducePartialResultsOnNetworkThread(int64_t timestamp_us)1146 void RTCStatsCollector::ProducePartialResultsOnNetworkThread(
1147     int64_t timestamp_us) {
1148   RTC_DCHECK(network_thread_->IsCurrent());
1149   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1150 
1151   // Touching |network_report_| on this thread is safe by this method because
1152   // |network_report_event_| is reset before this method is invoked.
1153   network_report_ = RTCStatsReport::Create(timestamp_us);
1154 
1155   std::map<std::string, cricket::TransportStats> transport_stats_by_name =
1156       pc_->GetTransportStatsByNames(transport_names_);
1157   std::map<std::string, CertificateStatsPair> transport_cert_stats =
1158       PrepareTransportCertificateStats_n(transport_stats_by_name);
1159 
1160   ProducePartialResultsOnNetworkThreadImpl(
1161       timestamp_us, transport_stats_by_name, transport_cert_stats,
1162       network_report_.get());
1163 
1164   // Signal that it is now safe to touch |network_report_| on the signaling
1165   // thread, and post a task to merge it into the final results.
1166   network_report_event_.Set();
1167   signaling_thread_->PostTask(
1168       RTC_FROM_HERE, rtc::Bind(&RTCStatsCollector::MergeNetworkReport_s, this));
1169 }
1170 
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)1171 void RTCStatsCollector::ProducePartialResultsOnNetworkThreadImpl(
1172     int64_t timestamp_us,
1173     const std::map<std::string, cricket::TransportStats>&
1174         transport_stats_by_name,
1175     const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
1176     RTCStatsReport* partial_report) {
1177   RTC_DCHECK(network_thread_->IsCurrent());
1178   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1179 
1180   ProduceCertificateStats_n(timestamp_us, transport_cert_stats, partial_report);
1181   ProduceCodecStats_n(timestamp_us, transceiver_stats_infos_, partial_report);
1182   ProduceIceCandidateAndPairStats_n(timestamp_us, transport_stats_by_name,
1183                                     call_stats_, partial_report);
1184   ProduceTransportStats_n(timestamp_us, transport_stats_by_name,
1185                           transport_cert_stats, partial_report);
1186   ProduceRTPStreamStats_n(timestamp_us, transceiver_stats_infos_,
1187                           partial_report);
1188 }
1189 
MergeNetworkReport_s()1190 void RTCStatsCollector::MergeNetworkReport_s() {
1191   RTC_DCHECK(signaling_thread_->IsCurrent());
1192   // The |network_report_event_| must be signaled for it to be safe to touch
1193   // |network_report_|. This is normally not blocking, but if
1194   // WaitForPendingRequest() is called while a request is pending, we might have
1195   // to wait until the network thread is done touching |network_report_|.
1196   network_report_event_.Wait(rtc::Event::kForever);
1197   if (!network_report_) {
1198     // Normally, MergeNetworkReport_s() is executed because it is posted from
1199     // the network thread. But if WaitForPendingRequest() is called while a
1200     // request is pending, an early call to MergeNetworkReport_s() is made,
1201     // merging the report and setting |network_report_| to null. If so, when the
1202     // previously posted MergeNetworkReport_s() is later executed, the report is
1203     // already null and nothing needs to be done here.
1204     return;
1205   }
1206   RTC_DCHECK_GT(num_pending_partial_reports_, 0);
1207   RTC_DCHECK(partial_report_);
1208   partial_report_->TakeMembersFrom(network_report_);
1209   network_report_ = nullptr;
1210   --num_pending_partial_reports_;
1211   // |network_report_| is currently the only partial report collected
1212   // asynchronously, so |num_pending_partial_reports_| must now be 0 and we are
1213   // ready to deliver the result.
1214   RTC_DCHECK_EQ(num_pending_partial_reports_, 0);
1215   cache_timestamp_us_ = partial_report_timestamp_us_;
1216   cached_report_ = partial_report_;
1217   partial_report_ = nullptr;
1218   transceiver_stats_infos_.clear();
1219   // Trace WebRTC Stats when getStats is called on Javascript.
1220   // This allows access to WebRTC stats from trace logs. To enable them,
1221   // select the "webrtc_stats" category when recording traces.
1222   TRACE_EVENT_INSTANT1("webrtc_stats", "webrtc_stats", "report",
1223                        cached_report_->ToJson());
1224 
1225   // Deliver report and clear |requests_|.
1226   std::vector<RequestInfo> requests;
1227   requests.swap(requests_);
1228   DeliverCachedReport(cached_report_, std::move(requests));
1229 }
1230 
DeliverCachedReport(rtc::scoped_refptr<const RTCStatsReport> cached_report,std::vector<RTCStatsCollector::RequestInfo> requests)1231 void RTCStatsCollector::DeliverCachedReport(
1232     rtc::scoped_refptr<const RTCStatsReport> cached_report,
1233     std::vector<RTCStatsCollector::RequestInfo> requests) {
1234   RTC_DCHECK(signaling_thread_->IsCurrent());
1235   RTC_DCHECK(!requests.empty());
1236   RTC_DCHECK(cached_report);
1237 
1238   for (const RequestInfo& request : requests) {
1239     if (request.filter_mode() == RequestInfo::FilterMode::kAll) {
1240       request.callback()->OnStatsDelivered(cached_report);
1241     } else {
1242       bool filter_by_sender_selector;
1243       rtc::scoped_refptr<RtpSenderInternal> sender_selector;
1244       rtc::scoped_refptr<RtpReceiverInternal> receiver_selector;
1245       if (request.filter_mode() == RequestInfo::FilterMode::kSenderSelector) {
1246         filter_by_sender_selector = true;
1247         sender_selector = request.sender_selector();
1248       } else {
1249         RTC_DCHECK(request.filter_mode() ==
1250                    RequestInfo::FilterMode::kReceiverSelector);
1251         filter_by_sender_selector = false;
1252         receiver_selector = request.receiver_selector();
1253       }
1254       request.callback()->OnStatsDelivered(CreateReportFilteredBySelector(
1255           filter_by_sender_selector, cached_report, sender_selector,
1256           receiver_selector));
1257     }
1258   }
1259 }
1260 
ProduceCertificateStats_n(int64_t timestamp_us,const std::map<std::string,CertificateStatsPair> & transport_cert_stats,RTCStatsReport * report) const1261 void RTCStatsCollector::ProduceCertificateStats_n(
1262     int64_t timestamp_us,
1263     const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
1264     RTCStatsReport* report) const {
1265   RTC_DCHECK(network_thread_->IsCurrent());
1266   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1267 
1268   for (const auto& transport_cert_stats_pair : transport_cert_stats) {
1269     if (transport_cert_stats_pair.second.local) {
1270       ProduceCertificateStatsFromSSLCertificateStats(
1271           timestamp_us, *transport_cert_stats_pair.second.local.get(), report);
1272     }
1273     if (transport_cert_stats_pair.second.remote) {
1274       ProduceCertificateStatsFromSSLCertificateStats(
1275           timestamp_us, *transport_cert_stats_pair.second.remote.get(), report);
1276     }
1277   }
1278 }
1279 
ProduceCodecStats_n(int64_t timestamp_us,const std::vector<RtpTransceiverStatsInfo> & transceiver_stats_infos,RTCStatsReport * report) const1280 void RTCStatsCollector::ProduceCodecStats_n(
1281     int64_t timestamp_us,
1282     const std::vector<RtpTransceiverStatsInfo>& transceiver_stats_infos,
1283     RTCStatsReport* report) const {
1284   RTC_DCHECK(network_thread_->IsCurrent());
1285   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1286 
1287   for (const auto& stats : transceiver_stats_infos) {
1288     if (!stats.mid) {
1289       continue;
1290     }
1291     const cricket::VoiceMediaInfo* voice_media_info =
1292         stats.track_media_info_map->voice_media_info();
1293     const cricket::VideoMediaInfo* video_media_info =
1294         stats.track_media_info_map->video_media_info();
1295     // Audio
1296     if (voice_media_info) {
1297       // Inbound
1298       for (const auto& pair : voice_media_info->receive_codecs) {
1299         report->AddStats(CodecStatsFromRtpCodecParameters(
1300             timestamp_us, *stats.mid, true, pair.second));
1301       }
1302       // Outbound
1303       for (const auto& pair : voice_media_info->send_codecs) {
1304         report->AddStats(CodecStatsFromRtpCodecParameters(
1305             timestamp_us, *stats.mid, false, pair.second));
1306       }
1307     }
1308     // Video
1309     if (video_media_info) {
1310       // Inbound
1311       for (const auto& pair : video_media_info->receive_codecs) {
1312         report->AddStats(CodecStatsFromRtpCodecParameters(
1313             timestamp_us, *stats.mid, true, pair.second));
1314       }
1315       // Outbound
1316       for (const auto& pair : video_media_info->send_codecs) {
1317         report->AddStats(CodecStatsFromRtpCodecParameters(
1318             timestamp_us, *stats.mid, false, pair.second));
1319       }
1320     }
1321   }
1322 }
1323 
ProduceDataChannelStats_s(int64_t timestamp_us,RTCStatsReport * report) const1324 void RTCStatsCollector::ProduceDataChannelStats_s(
1325     int64_t timestamp_us,
1326     RTCStatsReport* report) const {
1327   RTC_DCHECK_RUN_ON(signaling_thread_);
1328   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1329   std::vector<DataChannelStats> data_stats = pc_->GetDataChannelStats();
1330   for (const auto& stats : data_stats) {
1331     std::unique_ptr<RTCDataChannelStats> data_channel_stats(
1332         new RTCDataChannelStats(
1333             "RTCDataChannel_" + rtc::ToString(stats.internal_id),
1334             timestamp_us));
1335     data_channel_stats->label = std::move(stats.label);
1336     data_channel_stats->protocol = std::move(stats.protocol);
1337     data_channel_stats->data_channel_identifier = stats.id;
1338     data_channel_stats->state = DataStateToRTCDataChannelState(stats.state);
1339     data_channel_stats->messages_sent = stats.messages_sent;
1340     data_channel_stats->bytes_sent = stats.bytes_sent;
1341     data_channel_stats->messages_received = stats.messages_received;
1342     data_channel_stats->bytes_received = stats.bytes_received;
1343     report->AddStats(std::move(data_channel_stats));
1344   }
1345 }
1346 
ProduceIceCandidateAndPairStats_n(int64_t timestamp_us,const std::map<std::string,cricket::TransportStats> & transport_stats_by_name,const Call::Stats & call_stats,RTCStatsReport * report) const1347 void RTCStatsCollector::ProduceIceCandidateAndPairStats_n(
1348     int64_t timestamp_us,
1349     const std::map<std::string, cricket::TransportStats>&
1350         transport_stats_by_name,
1351     const Call::Stats& call_stats,
1352     RTCStatsReport* report) const {
1353   RTC_DCHECK(network_thread_->IsCurrent());
1354   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1355 
1356   for (const auto& entry : transport_stats_by_name) {
1357     const std::string& transport_name = entry.first;
1358     const cricket::TransportStats& transport_stats = entry.second;
1359     for (const auto& channel_stats : transport_stats.channel_stats) {
1360       std::string transport_id = RTCTransportStatsIDFromTransportChannel(
1361           transport_name, channel_stats.component);
1362       for (const cricket::ConnectionInfo& info :
1363            channel_stats.ice_transport_stats.connection_infos) {
1364         std::unique_ptr<RTCIceCandidatePairStats> candidate_pair_stats(
1365             new RTCIceCandidatePairStats(
1366                 RTCIceCandidatePairStatsIDFromConnectionInfo(info),
1367                 timestamp_us));
1368 
1369         candidate_pair_stats->transport_id = transport_id;
1370         // TODO(hbos): There could be other candidates that are not paired with
1371         // anything. We don't have a complete list. Local candidates come from
1372         // Port objects, and prflx candidates (both local and remote) are only
1373         // stored in candidate pairs. https://crbug.com/632723
1374         candidate_pair_stats->local_candidate_id = ProduceIceCandidateStats(
1375             timestamp_us, info.local_candidate, true, transport_id, report);
1376         candidate_pair_stats->remote_candidate_id = ProduceIceCandidateStats(
1377             timestamp_us, info.remote_candidate, false, transport_id, report);
1378         candidate_pair_stats->state =
1379             IceCandidatePairStateToRTCStatsIceCandidatePairState(info.state);
1380         candidate_pair_stats->priority = info.priority;
1381         candidate_pair_stats->nominated = info.nominated;
1382         // TODO(hbos): This writable is different than the spec. It goes to
1383         // false after a certain amount of time without a response passes.
1384         // https://crbug.com/633550
1385         candidate_pair_stats->writable = info.writable;
1386         candidate_pair_stats->bytes_sent =
1387             static_cast<uint64_t>(info.sent_total_bytes);
1388         candidate_pair_stats->bytes_received =
1389             static_cast<uint64_t>(info.recv_total_bytes);
1390         candidate_pair_stats->total_round_trip_time =
1391             static_cast<double>(info.total_round_trip_time_ms) /
1392             rtc::kNumMillisecsPerSec;
1393         if (info.current_round_trip_time_ms) {
1394           candidate_pair_stats->current_round_trip_time =
1395               static_cast<double>(*info.current_round_trip_time_ms) /
1396               rtc::kNumMillisecsPerSec;
1397         }
1398         if (info.best_connection) {
1399           // The bandwidth estimations we have are for the selected candidate
1400           // pair ("info.best_connection").
1401           RTC_DCHECK_GE(call_stats.send_bandwidth_bps, 0);
1402           RTC_DCHECK_GE(call_stats.recv_bandwidth_bps, 0);
1403           if (call_stats.send_bandwidth_bps > 0) {
1404             candidate_pair_stats->available_outgoing_bitrate =
1405                 static_cast<double>(call_stats.send_bandwidth_bps);
1406           }
1407           if (call_stats.recv_bandwidth_bps > 0) {
1408             candidate_pair_stats->available_incoming_bitrate =
1409                 static_cast<double>(call_stats.recv_bandwidth_bps);
1410           }
1411         }
1412         candidate_pair_stats->requests_received =
1413             static_cast<uint64_t>(info.recv_ping_requests);
1414         candidate_pair_stats->requests_sent = static_cast<uint64_t>(
1415             info.sent_ping_requests_before_first_response);
1416         candidate_pair_stats->responses_received =
1417             static_cast<uint64_t>(info.recv_ping_responses);
1418         candidate_pair_stats->responses_sent =
1419             static_cast<uint64_t>(info.sent_ping_responses);
1420         RTC_DCHECK_GE(info.sent_ping_requests_total,
1421                       info.sent_ping_requests_before_first_response);
1422         candidate_pair_stats->consent_requests_sent = static_cast<uint64_t>(
1423             info.sent_ping_requests_total -
1424             info.sent_ping_requests_before_first_response);
1425 
1426         report->AddStats(std::move(candidate_pair_stats));
1427       }
1428     }
1429   }
1430 }
1431 
ProduceMediaStreamStats_s(int64_t timestamp_us,RTCStatsReport * report) const1432 void RTCStatsCollector::ProduceMediaStreamStats_s(
1433     int64_t timestamp_us,
1434     RTCStatsReport* report) const {
1435   RTC_DCHECK(signaling_thread_->IsCurrent());
1436   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1437 
1438   std::map<std::string, std::vector<std::string>> track_ids;
1439 
1440   for (const auto& stats : transceiver_stats_infos_) {
1441     for (const auto& sender : stats.transceiver->senders()) {
1442       std::string track_id =
1443           RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
1444               kSender, sender->internal()->AttachmentId());
1445       for (auto& stream_id : sender->stream_ids()) {
1446         track_ids[stream_id].push_back(track_id);
1447       }
1448     }
1449     for (const auto& receiver : stats.transceiver->receivers()) {
1450       std::string track_id =
1451           RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
1452               kReceiver, receiver->internal()->AttachmentId());
1453       for (auto& stream : receiver->streams()) {
1454         track_ids[stream->id()].push_back(track_id);
1455       }
1456     }
1457   }
1458 
1459   // Build stats for each stream ID known.
1460   for (auto& it : track_ids) {
1461     std::unique_ptr<RTCMediaStreamStats> stream_stats(
1462         new RTCMediaStreamStats("RTCMediaStream_" + it.first, timestamp_us));
1463     stream_stats->stream_identifier = it.first;
1464     stream_stats->track_ids = it.second;
1465     report->AddStats(std::move(stream_stats));
1466   }
1467 }
1468 
ProduceMediaStreamTrackStats_s(int64_t timestamp_us,RTCStatsReport * report) const1469 void RTCStatsCollector::ProduceMediaStreamTrackStats_s(
1470     int64_t timestamp_us,
1471     RTCStatsReport* report) const {
1472   RTC_DCHECK(signaling_thread_->IsCurrent());
1473   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1474 
1475   for (const RtpTransceiverStatsInfo& stats : transceiver_stats_infos_) {
1476     std::vector<rtc::scoped_refptr<RtpSenderInternal>> senders;
1477     for (const auto& sender : stats.transceiver->senders()) {
1478       senders.push_back(sender->internal());
1479     }
1480     ProduceSenderMediaTrackStats(timestamp_us, *stats.track_media_info_map,
1481                                  senders, report);
1482 
1483     std::vector<rtc::scoped_refptr<RtpReceiverInternal>> receivers;
1484     for (const auto& receiver : stats.transceiver->receivers()) {
1485       receivers.push_back(receiver->internal());
1486     }
1487     ProduceReceiverMediaTrackStats(timestamp_us, *stats.track_media_info_map,
1488                                    receivers, report);
1489   }
1490 }
1491 
ProduceMediaSourceStats_s(int64_t timestamp_us,RTCStatsReport * report) const1492 void RTCStatsCollector::ProduceMediaSourceStats_s(
1493     int64_t timestamp_us,
1494     RTCStatsReport* report) const {
1495   RTC_DCHECK(signaling_thread_->IsCurrent());
1496   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1497 
1498   for (const RtpTransceiverStatsInfo& transceiver_stats_info :
1499        transceiver_stats_infos_) {
1500     const auto& track_media_info_map =
1501         transceiver_stats_info.track_media_info_map;
1502     for (const auto& sender : transceiver_stats_info.transceiver->senders()) {
1503       const auto& sender_internal = sender->internal();
1504       const auto& track = sender_internal->track();
1505       if (!track)
1506         continue;
1507       // TODO(https://crbug.com/webrtc/10771): The same track could be attached
1508       // to multiple senders which should result in multiple senders referencing
1509       // the same media-source stats. When all media source related metrics are
1510       // moved to the track's source (e.g. input frame rate is moved from
1511       // cricket::VideoSenderInfo to VideoTrackSourceInterface::Stats and audio
1512       // levels are moved to the corresponding audio track/source object), don't
1513       // create separate media source stats objects on a per-attachment basis.
1514       std::unique_ptr<RTCMediaSourceStats> media_source_stats;
1515       if (track->kind() == MediaStreamTrackInterface::kAudioKind) {
1516         auto audio_source_stats = std::make_unique<RTCAudioSourceStats>(
1517             RTCMediaSourceStatsIDFromKindAndAttachment(
1518                 cricket::MEDIA_TYPE_AUDIO, sender_internal->AttachmentId()),
1519             timestamp_us);
1520         // TODO(https://crbug.com/webrtc/10771): We shouldn't need to have an
1521         // SSRC assigned (there shouldn't need to exist a send-stream, created
1522         // by an O/A exchange) in order to read audio media-source stats.
1523         // TODO(https://crbug.com/webrtc/8694): SSRC 0 shouldn't be a magic
1524         // value indicating no SSRC.
1525         if (sender_internal->ssrc() != 0) {
1526           auto* voice_sender_info =
1527               track_media_info_map->GetVoiceSenderInfoBySsrc(
1528                   sender_internal->ssrc());
1529           if (voice_sender_info) {
1530             audio_source_stats->audio_level = DoubleAudioLevelFromIntAudioLevel(
1531                 voice_sender_info->audio_level);
1532             audio_source_stats->total_audio_energy =
1533                 voice_sender_info->total_input_energy;
1534             audio_source_stats->total_samples_duration =
1535                 voice_sender_info->total_input_duration;
1536           }
1537         }
1538         media_source_stats = std::move(audio_source_stats);
1539       } else {
1540         RTC_DCHECK_EQ(MediaStreamTrackInterface::kVideoKind, track->kind());
1541         auto video_source_stats = std::make_unique<RTCVideoSourceStats>(
1542             RTCMediaSourceStatsIDFromKindAndAttachment(
1543                 cricket::MEDIA_TYPE_VIDEO, sender_internal->AttachmentId()),
1544             timestamp_us);
1545         auto* video_track = static_cast<VideoTrackInterface*>(track.get());
1546         auto* video_source = video_track->GetSource();
1547         VideoTrackSourceInterface::Stats source_stats;
1548         if (video_source && video_source->GetStats(&source_stats)) {
1549           video_source_stats->width = source_stats.input_width;
1550           video_source_stats->height = source_stats.input_height;
1551         }
1552         // TODO(https://crbug.com/webrtc/10771): We shouldn't need to have an
1553         // SSRC assigned (there shouldn't need to exist a send-stream, created
1554         // by an O/A exchange) in order to get framesPerSecond.
1555         // TODO(https://crbug.com/webrtc/8694): SSRC 0 shouldn't be a magic
1556         // value indicating no SSRC.
1557         if (sender_internal->ssrc() != 0) {
1558           auto* video_sender_info =
1559               track_media_info_map->GetVideoSenderInfoBySsrc(
1560                   sender_internal->ssrc());
1561           if (video_sender_info) {
1562             video_source_stats->frames_per_second =
1563                 video_sender_info->framerate_input;
1564           }
1565         }
1566         media_source_stats = std::move(video_source_stats);
1567       }
1568       media_source_stats->track_identifier = track->id();
1569       media_source_stats->kind = track->kind();
1570       report->AddStats(std::move(media_source_stats));
1571     }
1572   }
1573 }
1574 
ProducePeerConnectionStats_s(int64_t timestamp_us,RTCStatsReport * report) const1575 void RTCStatsCollector::ProducePeerConnectionStats_s(
1576     int64_t timestamp_us,
1577     RTCStatsReport* report) const {
1578   RTC_DCHECK(signaling_thread_->IsCurrent());
1579   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1580 
1581   std::unique_ptr<RTCPeerConnectionStats> stats(
1582       new RTCPeerConnectionStats("RTCPeerConnection", timestamp_us));
1583   stats->data_channels_opened = internal_record_.data_channels_opened;
1584   stats->data_channels_closed = internal_record_.data_channels_closed;
1585   report->AddStats(std::move(stats));
1586 }
1587 
ProduceRTPStreamStats_n(int64_t timestamp_us,const std::vector<RtpTransceiverStatsInfo> & transceiver_stats_infos,RTCStatsReport * report) const1588 void RTCStatsCollector::ProduceRTPStreamStats_n(
1589     int64_t timestamp_us,
1590     const std::vector<RtpTransceiverStatsInfo>& transceiver_stats_infos,
1591     RTCStatsReport* report) const {
1592   RTC_DCHECK(network_thread_->IsCurrent());
1593   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1594 
1595   for (const RtpTransceiverStatsInfo& stats : transceiver_stats_infos) {
1596     if (stats.media_type == cricket::MEDIA_TYPE_AUDIO) {
1597       ProduceAudioRTPStreamStats_n(timestamp_us, stats, report);
1598     } else if (stats.media_type == cricket::MEDIA_TYPE_VIDEO) {
1599       ProduceVideoRTPStreamStats_n(timestamp_us, stats, report);
1600     } else {
1601       RTC_NOTREACHED();
1602     }
1603   }
1604 }
1605 
ProduceAudioRTPStreamStats_n(int64_t timestamp_us,const RtpTransceiverStatsInfo & stats,RTCStatsReport * report) const1606 void RTCStatsCollector::ProduceAudioRTPStreamStats_n(
1607     int64_t timestamp_us,
1608     const RtpTransceiverStatsInfo& stats,
1609     RTCStatsReport* report) const {
1610   RTC_DCHECK(network_thread_->IsCurrent());
1611   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1612 
1613   if (!stats.mid || !stats.transport_name) {
1614     return;
1615   }
1616   RTC_DCHECK(stats.track_media_info_map);
1617   const TrackMediaInfoMap& track_media_info_map = *stats.track_media_info_map;
1618   RTC_DCHECK(track_media_info_map.voice_media_info());
1619   std::string mid = *stats.mid;
1620   std::string transport_id = RTCTransportStatsIDFromTransportChannel(
1621       *stats.transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
1622   // Inbound
1623   for (const cricket::VoiceReceiverInfo& voice_receiver_info :
1624        track_media_info_map.voice_media_info()->receivers) {
1625     if (!voice_receiver_info.connected())
1626       continue;
1627     auto inbound_audio = std::make_unique<RTCInboundRTPStreamStats>(
1628         RTCInboundRTPStreamStatsIDFromSSRC(true, voice_receiver_info.ssrc()),
1629         timestamp_us);
1630     SetInboundRTPStreamStatsFromVoiceReceiverInfo(mid, voice_receiver_info,
1631                                                   inbound_audio.get());
1632     // TODO(hta): This lookup should look for the sender, not the track.
1633     rtc::scoped_refptr<AudioTrackInterface> audio_track =
1634         track_media_info_map.GetAudioTrack(voice_receiver_info);
1635     if (audio_track) {
1636       inbound_audio->track_id =
1637           RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
1638               kReceiver,
1639               track_media_info_map.GetAttachmentIdByTrack(audio_track).value());
1640     }
1641     inbound_audio->transport_id = transport_id;
1642     report->AddStats(std::move(inbound_audio));
1643   }
1644   // Outbound
1645   std::map<std::string, RTCOutboundRTPStreamStats*> audio_outbound_rtps;
1646   for (const cricket::VoiceSenderInfo& voice_sender_info :
1647        track_media_info_map.voice_media_info()->senders) {
1648     if (!voice_sender_info.connected())
1649       continue;
1650     auto outbound_audio = std::make_unique<RTCOutboundRTPStreamStats>(
1651         RTCOutboundRTPStreamStatsIDFromSSRC(true, voice_sender_info.ssrc()),
1652         timestamp_us);
1653     SetOutboundRTPStreamStatsFromVoiceSenderInfo(mid, voice_sender_info,
1654                                                  outbound_audio.get());
1655     rtc::scoped_refptr<AudioTrackInterface> audio_track =
1656         track_media_info_map.GetAudioTrack(voice_sender_info);
1657     if (audio_track) {
1658       int attachment_id =
1659           track_media_info_map.GetAttachmentIdByTrack(audio_track).value();
1660       outbound_audio->track_id =
1661           RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(kSender,
1662                                                                attachment_id);
1663       outbound_audio->media_source_id =
1664           RTCMediaSourceStatsIDFromKindAndAttachment(cricket::MEDIA_TYPE_AUDIO,
1665                                                      attachment_id);
1666     }
1667     outbound_audio->transport_id = transport_id;
1668     audio_outbound_rtps.insert(
1669         std::make_pair(outbound_audio->id(), outbound_audio.get()));
1670     report->AddStats(std::move(outbound_audio));
1671   }
1672   // Remote-inbound
1673   // These are Report Block-based, information sent from the remote endpoint,
1674   // providing metrics about our Outbound streams. We take advantage of the fact
1675   // that RTCOutboundRtpStreamStats, RTCCodecStats and RTCTransport have already
1676   // been added to the report.
1677   for (const cricket::VoiceSenderInfo& voice_sender_info :
1678        track_media_info_map.voice_media_info()->senders) {
1679     for (const auto& report_block_data : voice_sender_info.report_block_datas) {
1680       report->AddStats(ProduceRemoteInboundRtpStreamStatsFromReportBlockData(
1681           report_block_data, cricket::MEDIA_TYPE_AUDIO, audio_outbound_rtps,
1682           *report));
1683     }
1684   }
1685 }
1686 
ProduceVideoRTPStreamStats_n(int64_t timestamp_us,const RtpTransceiverStatsInfo & stats,RTCStatsReport * report) const1687 void RTCStatsCollector::ProduceVideoRTPStreamStats_n(
1688     int64_t timestamp_us,
1689     const RtpTransceiverStatsInfo& stats,
1690     RTCStatsReport* report) const {
1691   RTC_DCHECK(network_thread_->IsCurrent());
1692   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1693 
1694   if (!stats.mid || !stats.transport_name) {
1695     return;
1696   }
1697   RTC_DCHECK(stats.track_media_info_map);
1698   const TrackMediaInfoMap& track_media_info_map = *stats.track_media_info_map;
1699   RTC_DCHECK(track_media_info_map.video_media_info());
1700   std::string mid = *stats.mid;
1701   std::string transport_id = RTCTransportStatsIDFromTransportChannel(
1702       *stats.transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
1703   // Inbound
1704   for (const cricket::VideoReceiverInfo& video_receiver_info :
1705        track_media_info_map.video_media_info()->receivers) {
1706     if (!video_receiver_info.connected())
1707       continue;
1708     auto inbound_video = std::make_unique<RTCInboundRTPStreamStats>(
1709         RTCInboundRTPStreamStatsIDFromSSRC(false, video_receiver_info.ssrc()),
1710         timestamp_us);
1711     SetInboundRTPStreamStatsFromVideoReceiverInfo(mid, video_receiver_info,
1712                                                   inbound_video.get());
1713     rtc::scoped_refptr<VideoTrackInterface> video_track =
1714         track_media_info_map.GetVideoTrack(video_receiver_info);
1715     if (video_track) {
1716       inbound_video->track_id =
1717           RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
1718               kReceiver,
1719               track_media_info_map.GetAttachmentIdByTrack(video_track).value());
1720     }
1721     inbound_video->transport_id = transport_id;
1722     report->AddStats(std::move(inbound_video));
1723   }
1724   // Outbound
1725   std::map<std::string, RTCOutboundRTPStreamStats*> video_outbound_rtps;
1726   for (const cricket::VideoSenderInfo& video_sender_info :
1727        track_media_info_map.video_media_info()->senders) {
1728     if (!video_sender_info.connected())
1729       continue;
1730     auto outbound_video = std::make_unique<RTCOutboundRTPStreamStats>(
1731         RTCOutboundRTPStreamStatsIDFromSSRC(false, video_sender_info.ssrc()),
1732         timestamp_us);
1733     SetOutboundRTPStreamStatsFromVideoSenderInfo(mid, video_sender_info,
1734                                                  outbound_video.get());
1735     rtc::scoped_refptr<VideoTrackInterface> video_track =
1736         track_media_info_map.GetVideoTrack(video_sender_info);
1737     if (video_track) {
1738       int attachment_id =
1739           track_media_info_map.GetAttachmentIdByTrack(video_track).value();
1740       outbound_video->track_id =
1741           RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(kSender,
1742                                                                attachment_id);
1743       outbound_video->media_source_id =
1744           RTCMediaSourceStatsIDFromKindAndAttachment(cricket::MEDIA_TYPE_VIDEO,
1745                                                      attachment_id);
1746     }
1747     outbound_video->transport_id = transport_id;
1748     video_outbound_rtps.insert(
1749         std::make_pair(outbound_video->id(), outbound_video.get()));
1750     report->AddStats(std::move(outbound_video));
1751   }
1752   // Remote-inbound
1753   // These are Report Block-based, information sent from the remote endpoint,
1754   // providing metrics about our Outbound streams. We take advantage of the fact
1755   // that RTCOutboundRtpStreamStats, RTCCodecStats and RTCTransport have already
1756   // been added to the report.
1757   for (const cricket::VideoSenderInfo& video_sender_info :
1758        track_media_info_map.video_media_info()->senders) {
1759     for (const auto& report_block_data : video_sender_info.report_block_datas) {
1760       report->AddStats(ProduceRemoteInboundRtpStreamStatsFromReportBlockData(
1761           report_block_data, cricket::MEDIA_TYPE_VIDEO, video_outbound_rtps,
1762           *report));
1763     }
1764   }
1765 }
1766 
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) const1767 void RTCStatsCollector::ProduceTransportStats_n(
1768     int64_t timestamp_us,
1769     const std::map<std::string, cricket::TransportStats>&
1770         transport_stats_by_name,
1771     const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
1772     RTCStatsReport* report) const {
1773   RTC_DCHECK(network_thread_->IsCurrent());
1774   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1775 
1776   for (const auto& entry : transport_stats_by_name) {
1777     const std::string& transport_name = entry.first;
1778     const cricket::TransportStats& transport_stats = entry.second;
1779 
1780     // Get reference to RTCP channel, if it exists.
1781     std::string rtcp_transport_stats_id;
1782     for (const cricket::TransportChannelStats& channel_stats :
1783          transport_stats.channel_stats) {
1784       if (channel_stats.component == cricket::ICE_CANDIDATE_COMPONENT_RTCP) {
1785         rtcp_transport_stats_id = RTCTransportStatsIDFromTransportChannel(
1786             transport_name, channel_stats.component);
1787         break;
1788       }
1789     }
1790 
1791     // Get reference to local and remote certificates of this transport, if they
1792     // exist.
1793     const auto& certificate_stats_it =
1794         transport_cert_stats.find(transport_name);
1795     RTC_DCHECK(certificate_stats_it != transport_cert_stats.cend());
1796     std::string local_certificate_id;
1797     if (certificate_stats_it->second.local) {
1798       local_certificate_id = RTCCertificateIDFromFingerprint(
1799           certificate_stats_it->second.local->fingerprint);
1800     }
1801     std::string remote_certificate_id;
1802     if (certificate_stats_it->second.remote) {
1803       remote_certificate_id = RTCCertificateIDFromFingerprint(
1804           certificate_stats_it->second.remote->fingerprint);
1805     }
1806 
1807     // There is one transport stats for each channel.
1808     for (const cricket::TransportChannelStats& channel_stats :
1809          transport_stats.channel_stats) {
1810       std::unique_ptr<RTCTransportStats> transport_stats(
1811           new RTCTransportStats(RTCTransportStatsIDFromTransportChannel(
1812                                     transport_name, channel_stats.component),
1813                                 timestamp_us));
1814       transport_stats->bytes_sent = 0;
1815       transport_stats->packets_sent = 0;
1816       transport_stats->bytes_received = 0;
1817       transport_stats->packets_received = 0;
1818       transport_stats->dtls_state =
1819           DtlsTransportStateToRTCDtlsTransportState(channel_stats.dtls_state);
1820       transport_stats->selected_candidate_pair_changes =
1821           channel_stats.ice_transport_stats.selected_candidate_pair_changes;
1822       for (const cricket::ConnectionInfo& info :
1823            channel_stats.ice_transport_stats.connection_infos) {
1824         *transport_stats->bytes_sent += info.sent_total_bytes;
1825         *transport_stats->packets_sent +=
1826             info.sent_total_packets - info.sent_discarded_packets;
1827         *transport_stats->bytes_received += info.recv_total_bytes;
1828         *transport_stats->packets_received += info.packets_received;
1829         if (info.best_connection) {
1830           transport_stats->selected_candidate_pair_id =
1831               RTCIceCandidatePairStatsIDFromConnectionInfo(info);
1832         }
1833       }
1834       if (channel_stats.component != cricket::ICE_CANDIDATE_COMPONENT_RTCP &&
1835           !rtcp_transport_stats_id.empty()) {
1836         transport_stats->rtcp_transport_stats_id = rtcp_transport_stats_id;
1837       }
1838       if (!local_certificate_id.empty())
1839         transport_stats->local_certificate_id = local_certificate_id;
1840       if (!remote_certificate_id.empty())
1841         transport_stats->remote_certificate_id = remote_certificate_id;
1842       // Crypto information
1843       if (channel_stats.ssl_version_bytes) {
1844         char bytes[5];
1845         snprintf(bytes, sizeof(bytes), "%04X", channel_stats.ssl_version_bytes);
1846         transport_stats->tls_version = bytes;
1847       }
1848       if (channel_stats.ssl_cipher_suite != rtc::TLS_NULL_WITH_NULL_NULL &&
1849           rtc::SSLStreamAdapter::SslCipherSuiteToName(
1850               channel_stats.ssl_cipher_suite)
1851               .length()) {
1852         transport_stats->dtls_cipher =
1853             rtc::SSLStreamAdapter::SslCipherSuiteToName(
1854                 channel_stats.ssl_cipher_suite);
1855       }
1856       if (channel_stats.srtp_crypto_suite != rtc::SRTP_INVALID_CRYPTO_SUITE &&
1857           rtc::SrtpCryptoSuiteToName(channel_stats.srtp_crypto_suite)
1858               .length()) {
1859         transport_stats->srtp_cipher =
1860             rtc::SrtpCryptoSuiteToName(channel_stats.srtp_crypto_suite);
1861       }
1862       report->AddStats(std::move(transport_stats));
1863     }
1864   }
1865 }
1866 
1867 std::map<std::string, RTCStatsCollector::CertificateStatsPair>
PrepareTransportCertificateStats_n(const std::map<std::string,cricket::TransportStats> & transport_stats_by_name) const1868 RTCStatsCollector::PrepareTransportCertificateStats_n(
1869     const std::map<std::string, cricket::TransportStats>&
1870         transport_stats_by_name) const {
1871   RTC_DCHECK(network_thread_->IsCurrent());
1872   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1873 
1874   std::map<std::string, CertificateStatsPair> transport_cert_stats;
1875   for (const auto& entry : transport_stats_by_name) {
1876     const std::string& transport_name = entry.first;
1877 
1878     CertificateStatsPair certificate_stats_pair;
1879     rtc::scoped_refptr<rtc::RTCCertificate> local_certificate;
1880     if (pc_->GetLocalCertificate(transport_name, &local_certificate)) {
1881       certificate_stats_pair.local =
1882           local_certificate->GetSSLCertificateChain().GetStats();
1883     }
1884 
1885     std::unique_ptr<rtc::SSLCertChain> remote_cert_chain =
1886         pc_->GetRemoteSSLCertChain(transport_name);
1887     if (remote_cert_chain) {
1888       certificate_stats_pair.remote = remote_cert_chain->GetStats();
1889     }
1890 
1891     transport_cert_stats.insert(
1892         std::make_pair(transport_name, std::move(certificate_stats_pair)));
1893   }
1894   return transport_cert_stats;
1895 }
1896 
1897 std::vector<RTCStatsCollector::RtpTransceiverStatsInfo>
PrepareTransceiverStatsInfos_s_w() const1898 RTCStatsCollector::PrepareTransceiverStatsInfos_s_w() const {
1899   RTC_DCHECK(signaling_thread_->IsCurrent());
1900 
1901   std::vector<RtpTransceiverStatsInfo> transceiver_stats_infos;
1902   // These are used to invoke GetStats for all the media channels together in
1903   // one worker thread hop.
1904   std::map<cricket::VoiceMediaChannel*,
1905            std::unique_ptr<cricket::VoiceMediaInfo>>
1906       voice_stats;
1907   std::map<cricket::VideoMediaChannel*,
1908            std::unique_ptr<cricket::VideoMediaInfo>>
1909       video_stats;
1910 
1911   {
1912     rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1913 
1914     for (const auto& transceiver : pc_->GetTransceiversInternal()) {
1915       cricket::MediaType media_type = transceiver->media_type();
1916 
1917       // Prepare stats entry. The TrackMediaInfoMap will be filled in after the
1918       // stats have been fetched on the worker thread.
1919       transceiver_stats_infos.emplace_back();
1920       RtpTransceiverStatsInfo& stats = transceiver_stats_infos.back();
1921       stats.transceiver = transceiver->internal();
1922       stats.media_type = media_type;
1923 
1924       cricket::ChannelInterface* channel = transceiver->internal()->channel();
1925       if (!channel) {
1926         // The remaining fields require a BaseChannel.
1927         continue;
1928       }
1929 
1930       stats.mid = channel->content_name();
1931       stats.transport_name = channel->transport_name();
1932 
1933       if (media_type == cricket::MEDIA_TYPE_AUDIO) {
1934         auto* voice_channel = static_cast<cricket::VoiceChannel*>(channel);
1935         RTC_DCHECK(voice_stats.find(voice_channel->media_channel()) ==
1936                    voice_stats.end());
1937         voice_stats[voice_channel->media_channel()] =
1938             std::make_unique<cricket::VoiceMediaInfo>();
1939       } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1940         auto* video_channel = static_cast<cricket::VideoChannel*>(channel);
1941         RTC_DCHECK(video_stats.find(video_channel->media_channel()) ==
1942                    video_stats.end());
1943         video_stats[video_channel->media_channel()] =
1944             std::make_unique<cricket::VideoMediaInfo>();
1945       } else {
1946         RTC_NOTREACHED();
1947       }
1948     }
1949   }
1950 
1951   // We jump to the worker thread and call GetStats() on each media channel. At
1952   // the same time we construct the TrackMediaInfoMaps, which also needs info
1953   // from the worker thread. This minimizes the number of thread jumps.
1954   worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
1955     rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1956 
1957     for (const auto& entry : voice_stats) {
1958       if (!entry.first->GetStats(entry.second.get())) {
1959         RTC_LOG(LS_WARNING) << "Failed to get voice stats.";
1960       }
1961     }
1962     for (const auto& entry : video_stats) {
1963       if (!entry.first->GetStats(entry.second.get())) {
1964         RTC_LOG(LS_WARNING) << "Failed to get video stats.";
1965       }
1966     }
1967 
1968     // Create the TrackMediaInfoMap for each transceiver stats object.
1969     for (auto& stats : transceiver_stats_infos) {
1970       auto transceiver = stats.transceiver;
1971       std::unique_ptr<cricket::VoiceMediaInfo> voice_media_info;
1972       std::unique_ptr<cricket::VideoMediaInfo> video_media_info;
1973       if (transceiver->channel()) {
1974         cricket::MediaType media_type = transceiver->media_type();
1975         if (media_type == cricket::MEDIA_TYPE_AUDIO) {
1976           auto* voice_channel =
1977               static_cast<cricket::VoiceChannel*>(transceiver->channel());
1978           RTC_DCHECK(voice_stats[voice_channel->media_channel()]);
1979           voice_media_info =
1980               std::move(voice_stats[voice_channel->media_channel()]);
1981         } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1982           auto* video_channel =
1983               static_cast<cricket::VideoChannel*>(transceiver->channel());
1984           RTC_DCHECK(video_stats[video_channel->media_channel()]);
1985           video_media_info =
1986               std::move(video_stats[video_channel->media_channel()]);
1987         }
1988       }
1989       std::vector<rtc::scoped_refptr<RtpSenderInternal>> senders;
1990       for (const auto& sender : transceiver->senders()) {
1991         senders.push_back(sender->internal());
1992       }
1993       std::vector<rtc::scoped_refptr<RtpReceiverInternal>> receivers;
1994       for (const auto& receiver : transceiver->receivers()) {
1995         receivers.push_back(receiver->internal());
1996       }
1997       stats.track_media_info_map = std::make_unique<TrackMediaInfoMap>(
1998           std::move(voice_media_info), std::move(video_media_info), senders,
1999           receivers);
2000     }
2001   });
2002 
2003   return transceiver_stats_infos;
2004 }
2005 
PrepareTransportNames_s() const2006 std::set<std::string> RTCStatsCollector::PrepareTransportNames_s() const {
2007   RTC_DCHECK(signaling_thread_->IsCurrent());
2008   rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
2009 
2010   std::set<std::string> transport_names;
2011   for (const auto& transceiver : pc_->GetTransceiversInternal()) {
2012     if (transceiver->internal()->channel()) {
2013       transport_names.insert(
2014           transceiver->internal()->channel()->transport_name());
2015     }
2016   }
2017   if (pc_->rtp_data_channel()) {
2018     transport_names.insert(pc_->rtp_data_channel()->transport_name());
2019   }
2020   if (pc_->sctp_transport_name()) {
2021     transport_names.insert(*pc_->sctp_transport_name());
2022   }
2023   return transport_names;
2024 }
2025 
OnRtpDataChannelCreated(RtpDataChannel * channel)2026 void RTCStatsCollector::OnRtpDataChannelCreated(RtpDataChannel* channel) {
2027   channel->SignalOpened.connect(this, &RTCStatsCollector::OnDataChannelOpened);
2028   channel->SignalClosed.connect(this, &RTCStatsCollector::OnDataChannelClosed);
2029 }
2030 
OnSctpDataChannelCreated(SctpDataChannel * channel)2031 void RTCStatsCollector::OnSctpDataChannelCreated(SctpDataChannel* channel) {
2032   channel->SignalOpened.connect(this, &RTCStatsCollector::OnDataChannelOpened);
2033   channel->SignalClosed.connect(this, &RTCStatsCollector::OnDataChannelClosed);
2034 }
2035 
OnDataChannelOpened(DataChannelInterface * channel)2036 void RTCStatsCollector::OnDataChannelOpened(DataChannelInterface* channel) {
2037   RTC_DCHECK(signaling_thread_->IsCurrent());
2038   bool result = internal_record_.opened_data_channels
2039                     .insert(reinterpret_cast<uintptr_t>(channel))
2040                     .second;
2041   ++internal_record_.data_channels_opened;
2042   RTC_DCHECK(result);
2043 }
2044 
OnDataChannelClosed(DataChannelInterface * channel)2045 void RTCStatsCollector::OnDataChannelClosed(DataChannelInterface* channel) {
2046   RTC_DCHECK(signaling_thread_->IsCurrent());
2047   // Only channels that have been fully opened (and have increased the
2048   // |data_channels_opened_| counter) increase the closed counter.
2049   if (internal_record_.opened_data_channels.erase(
2050           reinterpret_cast<uintptr_t>(channel))) {
2051     ++internal_record_.data_channels_closed;
2052   }
2053 }
2054 
CandidateTypeToRTCIceCandidateTypeForTesting(const std::string & type)2055 const char* CandidateTypeToRTCIceCandidateTypeForTesting(
2056     const std::string& type) {
2057   return CandidateTypeToRTCIceCandidateType(type);
2058 }
2059 
DataStateToRTCDataChannelStateForTesting(DataChannelInterface::DataState state)2060 const char* DataStateToRTCDataChannelStateForTesting(
2061     DataChannelInterface::DataState state) {
2062   return DataStateToRTCDataChannelState(state);
2063 }
2064 
2065 }  // namespace webrtc
2066