blob: ab12c657723059b23eed0ca6373cb49729bd9b02 [file] [log] [blame]
hbosd565b732016-08-30 14:04:35 -07001/*
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
Steve Anton10542f22019-01-11 09:11:00 -080011#include "pc/rtc_stats_collector.h"
hbosd565b732016-08-30 14:04:35 -070012
13#include <memory>
Steve Anton36b29d12017-10-30 09:57:42 -070014#include <string>
hbosd565b732016-08-30 14:04:35 -070015#include <utility>
16#include <vector>
17
Patrik Höglunde2d6a062017-10-05 14:53:33 +020018#include "api/candidate.h"
Steve Anton10542f22019-01-11 09:11:00 -080019#include "api/media_stream_interface.h"
20#include "api/peer_connection_interface.h"
Henrik Boström2e069262019-04-09 13:59:31 +020021#include "api/video/video_content_type.h"
Steve Anton10542f22019-01-11 09:11:00 -080022#include "media/base/media_channel.h"
23#include "p2p/base/p2p_constants.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "p2p/base/port.h"
Steve Anton10542f22019-01-11 09:11:00 -080025#include "pc/peer_connection.h"
26#include "pc/rtc_stats_traversal.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020027#include "rtc_base/checks.h"
Jonas Olsson43568dd2018-06-11 16:25:54 +020028#include "rtc_base/strings/string_builder.h"
Steve Anton10542f22019-01-11 09:11:00 -080029#include "rtc_base/time_utils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020030#include "rtc_base/trace_event.h"
hbosd565b732016-08-30 14:04:35 -070031
32namespace webrtc {
33
hboscc555c52016-10-18 12:48:31 -070034namespace {
35
Henrik Boström646fda02019-05-22 15:49:42 +020036// TODO(https://crbug.com/webrtc/10656): Consider making IDs less predictable.
hbos2fa7c672016-10-24 04:00:05 -070037std::string RTCCertificateIDFromFingerprint(const std::string& fingerprint) {
38 return "RTCCertificate_" + fingerprint;
39}
40
Steve Anton57858b32018-02-15 15:19:50 -080041std::string RTCCodecStatsIDFromMidDirectionAndPayload(const std::string& mid,
42 bool inbound,
43 uint32_t payload_type) {
Jonas Olsson43568dd2018-06-11 16:25:54 +020044 char buf[1024];
45 rtc::SimpleStringBuilder sb(buf);
46 sb << "RTCCodec_" << mid << (inbound ? "_Inbound_" : "_Outbound_")
47 << payload_type;
48 return sb.str();
hbos0adb8282016-11-23 02:32:06 -080049}
50
hbos2fa7c672016-10-24 04:00:05 -070051std::string RTCIceCandidatePairStatsIDFromConnectionInfo(
52 const cricket::ConnectionInfo& info) {
Jonas Olsson43568dd2018-06-11 16:25:54 +020053 char buf[4096];
54 rtc::SimpleStringBuilder sb(buf);
55 sb << "RTCIceCandidatePair_" << info.local_candidate.id() << "_"
56 << info.remote_candidate.id();
57 return sb.str();
hbos2fa7c672016-10-24 04:00:05 -070058}
59
Harald Alvestranda3dab842018-01-14 09:18:58 +010060const char kSender[] = "sender";
61const char kReceiver[] = "receiver";
62
63std::string RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
64 const char* direction,
Harald Alvestrandc72af932018-01-11 17:18:19 +010065 int attachment_id) {
Jonas Olsson43568dd2018-06-11 16:25:54 +020066 char buf[1024];
67 rtc::SimpleStringBuilder sb(buf);
68 sb << "RTCMediaStreamTrack_" << direction << "_" << attachment_id;
69 return sb.str();
hbos09bc1282016-11-08 06:29:22 -080070}
71
hbos2fa7c672016-10-24 04:00:05 -070072std::string RTCTransportStatsIDFromTransportChannel(
Jonas Olssona4d87372019-07-05 19:08:33 +020073 const std::string& transport_name,
74 int channel_component) {
Jonas Olsson43568dd2018-06-11 16:25:54 +020075 char buf[1024];
76 rtc::SimpleStringBuilder sb(buf);
77 sb << "RTCTransport_" << transport_name << "_" << channel_component;
78 return sb.str();
hbos2fa7c672016-10-24 04:00:05 -070079}
80
hboseeafe942016-11-01 03:00:17 -070081std::string RTCInboundRTPStreamStatsIDFromSSRC(bool audio, uint32_t ssrc) {
Jonas Olsson43568dd2018-06-11 16:25:54 +020082 char buf[1024];
83 rtc::SimpleStringBuilder sb(buf);
84 sb << "RTCInboundRTP" << (audio ? "Audio" : "Video") << "Stream_" << ssrc;
85 return sb.str();
hboseeafe942016-11-01 03:00:17 -070086}
87
hbos6ded1902016-11-01 01:50:46 -070088std::string RTCOutboundRTPStreamStatsIDFromSSRC(bool audio, uint32_t ssrc) {
Jonas Olsson43568dd2018-06-11 16:25:54 +020089 char buf[1024];
90 rtc::SimpleStringBuilder sb(buf);
91 sb << "RTCOutboundRTP" << (audio ? "Audio" : "Video") << "Stream_" << ssrc;
92 return sb.str();
hbos6ded1902016-11-01 01:50:46 -070093}
94
Henrik Boström8605fbf2019-06-24 16:44:51 +020095std::string RTCRemoteInboundRtpStreamStatsIdFromSourceSsrc(
Henrik Boström883eefc2019-05-27 13:40:25 +020096 cricket::MediaType media_type,
Henrik Boström883eefc2019-05-27 13:40:25 +020097 uint32_t source_ssrc) {
98 char buf[1024];
99 rtc::SimpleStringBuilder sb(buf);
100 sb << "RTCRemoteInboundRtp"
101 << (media_type == cricket::MEDIA_TYPE_AUDIO ? "Audio" : "Video")
Henrik Boström8605fbf2019-06-24 16:44:51 +0200102 << "Stream_" << source_ssrc;
Henrik Boström883eefc2019-05-27 13:40:25 +0200103 return sb.str();
104}
105
Henrik Boström646fda02019-05-22 15:49:42 +0200106std::string RTCMediaSourceStatsIDFromKindAndAttachment(
107 cricket::MediaType media_type,
108 int attachment_id) {
109 char buf[1024];
110 rtc::SimpleStringBuilder sb(buf);
111 sb << "RTC" << (media_type == cricket::MEDIA_TYPE_AUDIO ? "Audio" : "Video")
112 << "Source_" << attachment_id;
113 return sb.str();
114}
115
hbosab9f6e42016-10-07 02:18:47 -0700116const char* CandidateTypeToRTCIceCandidateType(const std::string& type) {
117 if (type == cricket::LOCAL_PORT_TYPE)
118 return RTCIceCandidateType::kHost;
119 if (type == cricket::STUN_PORT_TYPE)
120 return RTCIceCandidateType::kSrflx;
121 if (type == cricket::PRFLX_PORT_TYPE)
122 return RTCIceCandidateType::kPrflx;
123 if (type == cricket::RELAY_PORT_TYPE)
124 return RTCIceCandidateType::kRelay;
125 RTC_NOTREACHED();
126 return nullptr;
127}
128
hboscc555c52016-10-18 12:48:31 -0700129const char* DataStateToRTCDataChannelState(
130 DataChannelInterface::DataState state) {
131 switch (state) {
132 case DataChannelInterface::kConnecting:
133 return RTCDataChannelState::kConnecting;
134 case DataChannelInterface::kOpen:
135 return RTCDataChannelState::kOpen;
136 case DataChannelInterface::kClosing:
137 return RTCDataChannelState::kClosing;
138 case DataChannelInterface::kClosed:
139 return RTCDataChannelState::kClosed;
140 default:
141 RTC_NOTREACHED();
142 return nullptr;
143 }
144}
145
hbos06495bc2017-01-02 08:08:18 -0800146const char* IceCandidatePairStateToRTCStatsIceCandidatePairState(
147 cricket::IceCandidatePairState state) {
148 switch (state) {
149 case cricket::IceCandidatePairState::WAITING:
150 return RTCStatsIceCandidatePairState::kWaiting;
151 case cricket::IceCandidatePairState::IN_PROGRESS:
152 return RTCStatsIceCandidatePairState::kInProgress;
153 case cricket::IceCandidatePairState::SUCCEEDED:
154 return RTCStatsIceCandidatePairState::kSucceeded;
155 case cricket::IceCandidatePairState::FAILED:
156 return RTCStatsIceCandidatePairState::kFailed;
157 default:
158 RTC_NOTREACHED();
159 return nullptr;
160 }
161}
162
hbos7064d592017-01-16 07:38:02 -0800163const char* DtlsTransportStateToRTCDtlsTransportState(
164 cricket::DtlsTransportState state) {
165 switch (state) {
166 case cricket::DTLS_TRANSPORT_NEW:
167 return RTCDtlsTransportState::kNew;
168 case cricket::DTLS_TRANSPORT_CONNECTING:
169 return RTCDtlsTransportState::kConnecting;
170 case cricket::DTLS_TRANSPORT_CONNECTED:
171 return RTCDtlsTransportState::kConnected;
172 case cricket::DTLS_TRANSPORT_CLOSED:
173 return RTCDtlsTransportState::kClosed;
174 case cricket::DTLS_TRANSPORT_FAILED:
175 return RTCDtlsTransportState::kFailed;
176 default:
177 RTC_NOTREACHED();
178 return nullptr;
179 }
180}
181
Gary Liu37e489c2017-11-21 10:49:36 -0800182const char* NetworkAdapterTypeToStatsType(rtc::AdapterType type) {
183 switch (type) {
184 case rtc::ADAPTER_TYPE_CELLULAR:
185 return RTCNetworkType::kCellular;
186 case rtc::ADAPTER_TYPE_ETHERNET:
187 return RTCNetworkType::kEthernet;
188 case rtc::ADAPTER_TYPE_WIFI:
189 return RTCNetworkType::kWifi;
190 case rtc::ADAPTER_TYPE_VPN:
191 return RTCNetworkType::kVpn;
192 case rtc::ADAPTER_TYPE_UNKNOWN:
193 case rtc::ADAPTER_TYPE_LOOPBACK:
Qingsi Wang9f1de692018-06-28 15:38:09 -0700194 case rtc::ADAPTER_TYPE_ANY:
Gary Liu37e489c2017-11-21 10:49:36 -0800195 return RTCNetworkType::kUnknown;
196 }
197 RTC_NOTREACHED();
198 return nullptr;
199}
200
Henrik Boströmce33b6a2019-05-28 17:42:38 +0200201const char* QualityLimitationReasonToRTCQualityLimitationReason(
202 QualityLimitationReason reason) {
203 switch (reason) {
204 case QualityLimitationReason::kNone:
205 return RTCQualityLimitationReason::kNone;
206 case QualityLimitationReason::kCpu:
207 return RTCQualityLimitationReason::kCpu;
208 case QualityLimitationReason::kBandwidth:
209 return RTCQualityLimitationReason::kBandwidth;
210 case QualityLimitationReason::kOther:
211 return RTCQualityLimitationReason::kOther;
212 }
213}
214
hbos9e302742017-01-20 02:47:10 -0800215double DoubleAudioLevelFromIntAudioLevel(int audio_level) {
216 RTC_DCHECK_GE(audio_level, 0);
217 RTC_DCHECK_LE(audio_level, 32767);
218 return audio_level / 32767.0;
219}
220
hbos0adb8282016-11-23 02:32:06 -0800221std::unique_ptr<RTCCodecStats> CodecStatsFromRtpCodecParameters(
Steve Anton57858b32018-02-15 15:19:50 -0800222 uint64_t timestamp_us,
223 const std::string& mid,
224 bool inbound,
hbos0adb8282016-11-23 02:32:06 -0800225 const RtpCodecParameters& codec_params) {
226 RTC_DCHECK_GE(codec_params.payload_type, 0);
227 RTC_DCHECK_LE(codec_params.payload_type, 127);
deadbeefe702b302017-02-04 12:09:01 -0800228 RTC_DCHECK(codec_params.clock_rate);
hbos0adb8282016-11-23 02:32:06 -0800229 uint32_t payload_type = static_cast<uint32_t>(codec_params.payload_type);
230 std::unique_ptr<RTCCodecStats> codec_stats(new RTCCodecStats(
Steve Anton57858b32018-02-15 15:19:50 -0800231 RTCCodecStatsIDFromMidDirectionAndPayload(mid, inbound, payload_type),
hbos0adb8282016-11-23 02:32:06 -0800232 timestamp_us));
233 codec_stats->payload_type = payload_type;
hbos13f54b22017-02-28 06:56:04 -0800234 codec_stats->mime_type = codec_params.mime_type();
deadbeefe702b302017-02-04 12:09:01 -0800235 if (codec_params.clock_rate) {
236 codec_stats->clock_rate = static_cast<uint32_t>(*codec_params.clock_rate);
237 }
hbos0adb8282016-11-23 02:32:06 -0800238 return codec_stats;
239}
240
hbos09bc1282016-11-08 06:29:22 -0800241void SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
242 const MediaStreamTrackInterface& track,
243 RTCMediaStreamTrackStats* track_stats) {
244 track_stats->track_identifier = track.id();
245 track_stats->ended = (track.state() == MediaStreamTrackInterface::kEnded);
246}
247
hbos820f5782016-11-22 03:16:50 -0800248// Provides the media independent counters (both audio and video).
hboseeafe942016-11-01 03:00:17 -0700249void SetInboundRTPStreamStatsFromMediaReceiverInfo(
250 const cricket::MediaReceiverInfo& media_receiver_info,
251 RTCInboundRTPStreamStats* inbound_stats) {
252 RTC_DCHECK(inbound_stats);
hbos3443bb72017-02-07 06:28:11 -0800253 inbound_stats->ssrc = media_receiver_info.ssrc();
Harald Alvestrand89061872018-01-02 14:08:34 +0100254 // TODO(hbos): Support the remote case. https://crbug.com/657855
hboseeafe942016-11-01 03:00:17 -0700255 inbound_stats->is_remote = false;
hboseeafe942016-11-01 03:00:17 -0700256 inbound_stats->packets_received =
257 static_cast<uint32_t>(media_receiver_info.packets_rcvd);
258 inbound_stats->bytes_received =
Niels Möllerac0a4cb2019-10-09 15:01:33 +0200259 static_cast<uint64_t>(media_receiver_info.payload_bytes_rcvd);
260 inbound_stats->header_bytes_received =
261 static_cast<uint64_t>(media_receiver_info.header_and_padding_bytes_rcvd);
hbos02cd4d62016-12-09 04:19:44 -0800262 inbound_stats->packets_lost =
Harald Alvestrand719487e2017-12-13 12:26:04 +0100263 static_cast<int32_t>(media_receiver_info.packets_lost);
hboseeafe942016-11-01 03:00:17 -0700264}
265
266void SetInboundRTPStreamStatsFromVoiceReceiverInfo(
Steve Anton57858b32018-02-15 15:19:50 -0800267 const std::string& mid,
hboseeafe942016-11-01 03:00:17 -0700268 const cricket::VoiceReceiverInfo& voice_receiver_info,
hbos820f5782016-11-22 03:16:50 -0800269 RTCInboundRTPStreamStats* inbound_audio) {
Jonas Olssona4d87372019-07-05 19:08:33 +0200270 SetInboundRTPStreamStatsFromMediaReceiverInfo(voice_receiver_info,
271 inbound_audio);
hbos820f5782016-11-22 03:16:50 -0800272 inbound_audio->media_type = "audio";
Philipp Hancke3bc01662018-08-28 14:55:03 +0200273 inbound_audio->kind = "audio";
hbos585a9b12017-02-07 04:59:16 -0800274 if (voice_receiver_info.codec_payload_type) {
Steve Anton57858b32018-02-15 15:19:50 -0800275 inbound_audio->codec_id = RTCCodecStatsIDFromMidDirectionAndPayload(
276 mid, true, *voice_receiver_info.codec_payload_type);
hbos585a9b12017-02-07 04:59:16 -0800277 }
Jonas Olssona4d87372019-07-05 19:08:33 +0200278 inbound_audio->jitter = static_cast<double>(voice_receiver_info.jitter_ms) /
279 rtc::kNumMillisecsPerSec;
hbos820f5782016-11-22 03:16:50 -0800280 // |fir_count|, |pli_count| and |sli_count| are only valid for video and are
281 // purposefully left undefined for audio.
Henrik Boström01738c62019-04-15 17:32:00 +0200282 if (voice_receiver_info.last_packet_received_timestamp_ms) {
283 inbound_audio->last_packet_received_timestamp =
284 static_cast<double>(
285 *voice_receiver_info.last_packet_received_timestamp_ms) /
286 rtc::kNumMillisecsPerSec;
287 }
Åsa Perssonfcf79cc2019-10-22 15:23:44 +0200288 if (voice_receiver_info.estimated_playout_ntp_timestamp_ms) {
289 inbound_audio->estimated_playout_timestamp = static_cast<double>(
290 *voice_receiver_info.estimated_playout_ntp_timestamp_ms);
291 }
Ivo Creusen8d8ffdb2019-04-30 09:45:21 +0200292 inbound_audio->fec_packets_received =
293 voice_receiver_info.fec_packets_received;
294 inbound_audio->fec_packets_discarded =
295 voice_receiver_info.fec_packets_discarded;
hboseeafe942016-11-01 03:00:17 -0700296}
297
298void SetInboundRTPStreamStatsFromVideoReceiverInfo(
Steve Anton57858b32018-02-15 15:19:50 -0800299 const std::string& mid,
hboseeafe942016-11-01 03:00:17 -0700300 const cricket::VideoReceiverInfo& video_receiver_info,
hbos820f5782016-11-22 03:16:50 -0800301 RTCInboundRTPStreamStats* inbound_video) {
Jonas Olssona4d87372019-07-05 19:08:33 +0200302 SetInboundRTPStreamStatsFromMediaReceiverInfo(video_receiver_info,
303 inbound_video);
hbos820f5782016-11-22 03:16:50 -0800304 inbound_video->media_type = "video";
Philipp Hancke3bc01662018-08-28 14:55:03 +0200305 inbound_video->kind = "video";
hbos585a9b12017-02-07 04:59:16 -0800306 if (video_receiver_info.codec_payload_type) {
Steve Anton57858b32018-02-15 15:19:50 -0800307 inbound_video->codec_id = RTCCodecStatsIDFromMidDirectionAndPayload(
308 mid, true, *video_receiver_info.codec_payload_type);
hbos585a9b12017-02-07 04:59:16 -0800309 }
hbos820f5782016-11-22 03:16:50 -0800310 inbound_video->fir_count =
311 static_cast<uint32_t>(video_receiver_info.firs_sent);
312 inbound_video->pli_count =
313 static_cast<uint32_t>(video_receiver_info.plis_sent);
314 inbound_video->nack_count =
315 static_cast<uint32_t>(video_receiver_info.nacks_sent);
hbos6769c492017-01-02 08:35:13 -0800316 inbound_video->frames_decoded = video_receiver_info.frames_decoded;
Rasmus Brandt2efae772019-06-27 14:29:34 +0200317 inbound_video->key_frames_decoded = video_receiver_info.key_frames_decoded;
hbosa51d4f32017-02-16 05:34:48 -0800318 if (video_receiver_info.qp_sum)
319 inbound_video->qp_sum = *video_receiver_info.qp_sum;
Johannes Kronbfd343b2019-07-01 10:07:50 +0200320 inbound_video->total_decode_time =
321 static_cast<double>(video_receiver_info.total_decode_time_ms) /
322 rtc::kNumMillisecsPerSec;
Henrik Boström01738c62019-04-15 17:32:00 +0200323 if (video_receiver_info.last_packet_received_timestamp_ms) {
324 inbound_video->last_packet_received_timestamp =
325 static_cast<double>(
326 *video_receiver_info.last_packet_received_timestamp_ms) /
327 rtc::kNumMillisecsPerSec;
328 }
Åsa Perssonfcf79cc2019-10-22 15:23:44 +0200329 if (video_receiver_info.estimated_playout_ntp_timestamp_ms) {
330 inbound_video->estimated_playout_timestamp = static_cast<double>(
331 *video_receiver_info.estimated_playout_ntp_timestamp_ms);
332 }
Henrik Boström2e069262019-04-09 13:59:31 +0200333 // TODO(https://crbug.com/webrtc/10529): When info's |content_info| is
334 // optional, support the "unspecified" value.
335 if (video_receiver_info.content_type == VideoContentType::SCREENSHARE)
336 inbound_video->content_type = RTCContentType::kScreenshare;
Henrik Boström6b430862019-08-16 13:09:51 +0200337 if (!video_receiver_info.decoder_implementation_name.empty()) {
338 inbound_video->decoder_implementation =
339 video_receiver_info.decoder_implementation_name;
340 }
hboseeafe942016-11-01 03:00:17 -0700341}
342
hbos820f5782016-11-22 03:16:50 -0800343// Provides the media independent counters (both audio and video).
hbos6ded1902016-11-01 01:50:46 -0700344void SetOutboundRTPStreamStatsFromMediaSenderInfo(
345 const cricket::MediaSenderInfo& media_sender_info,
346 RTCOutboundRTPStreamStats* outbound_stats) {
347 RTC_DCHECK(outbound_stats);
hbos3443bb72017-02-07 06:28:11 -0800348 outbound_stats->ssrc = media_sender_info.ssrc();
Harald Alvestrand89061872018-01-02 14:08:34 +0100349 // TODO(hbos): Support the remote case. https://crbug.com/657856
hbos6ded1902016-11-01 01:50:46 -0700350 outbound_stats->is_remote = false;
hbos6ded1902016-11-01 01:50:46 -0700351 outbound_stats->packets_sent =
352 static_cast<uint32_t>(media_sender_info.packets_sent);
Henrik Boströmcf96e0f2019-04-17 13:51:53 +0200353 outbound_stats->retransmitted_packets_sent =
354 media_sender_info.retransmitted_packets_sent;
hbos6ded1902016-11-01 01:50:46 -0700355 outbound_stats->bytes_sent =
Niels Möllerac0a4cb2019-10-09 15:01:33 +0200356 static_cast<uint64_t>(media_sender_info.payload_bytes_sent);
357 outbound_stats->header_bytes_sent =
358 static_cast<uint64_t>(media_sender_info.header_and_padding_bytes_sent);
Henrik Boströmcf96e0f2019-04-17 13:51:53 +0200359 outbound_stats->retransmitted_bytes_sent =
360 media_sender_info.retransmitted_bytes_sent;
hbos6ded1902016-11-01 01:50:46 -0700361}
362
363void SetOutboundRTPStreamStatsFromVoiceSenderInfo(
Steve Anton57858b32018-02-15 15:19:50 -0800364 const std::string& mid,
hbos6ded1902016-11-01 01:50:46 -0700365 const cricket::VoiceSenderInfo& voice_sender_info,
366 RTCOutboundRTPStreamStats* outbound_audio) {
Jonas Olssona4d87372019-07-05 19:08:33 +0200367 SetOutboundRTPStreamStatsFromMediaSenderInfo(voice_sender_info,
368 outbound_audio);
hbos6ded1902016-11-01 01:50:46 -0700369 outbound_audio->media_type = "audio";
Philipp Hancke3bc01662018-08-28 14:55:03 +0200370 outbound_audio->kind = "audio";
hbos585a9b12017-02-07 04:59:16 -0800371 if (voice_sender_info.codec_payload_type) {
Steve Anton57858b32018-02-15 15:19:50 -0800372 outbound_audio->codec_id = RTCCodecStatsIDFromMidDirectionAndPayload(
373 mid, false, *voice_sender_info.codec_payload_type);
hbos585a9b12017-02-07 04:59:16 -0800374 }
hbos6ded1902016-11-01 01:50:46 -0700375 // |fir_count|, |pli_count| and |sli_count| are only valid for video and are
376 // purposefully left undefined for audio.
377}
378
379void SetOutboundRTPStreamStatsFromVideoSenderInfo(
Steve Anton57858b32018-02-15 15:19:50 -0800380 const std::string& mid,
hbos6ded1902016-11-01 01:50:46 -0700381 const cricket::VideoSenderInfo& video_sender_info,
382 RTCOutboundRTPStreamStats* outbound_video) {
Jonas Olssona4d87372019-07-05 19:08:33 +0200383 SetOutboundRTPStreamStatsFromMediaSenderInfo(video_sender_info,
384 outbound_video);
hbos6ded1902016-11-01 01:50:46 -0700385 outbound_video->media_type = "video";
Philipp Hancke3bc01662018-08-28 14:55:03 +0200386 outbound_video->kind = "video";
hbos585a9b12017-02-07 04:59:16 -0800387 if (video_sender_info.codec_payload_type) {
Steve Anton57858b32018-02-15 15:19:50 -0800388 outbound_video->codec_id = RTCCodecStatsIDFromMidDirectionAndPayload(
389 mid, false, *video_sender_info.codec_payload_type);
hbos585a9b12017-02-07 04:59:16 -0800390 }
hbos6ded1902016-11-01 01:50:46 -0700391 outbound_video->fir_count =
392 static_cast<uint32_t>(video_sender_info.firs_rcvd);
393 outbound_video->pli_count =
394 static_cast<uint32_t>(video_sender_info.plis_rcvd);
395 outbound_video->nack_count =
396 static_cast<uint32_t>(video_sender_info.nacks_rcvd);
hbos6769c492017-01-02 08:35:13 -0800397 if (video_sender_info.qp_sum)
398 outbound_video->qp_sum = *video_sender_info.qp_sum;
399 outbound_video->frames_encoded = video_sender_info.frames_encoded;
Rasmus Brandt2efae772019-06-27 14:29:34 +0200400 outbound_video->key_frames_encoded = video_sender_info.key_frames_encoded;
Henrik Boströmf71362f2019-04-08 16:14:23 +0200401 outbound_video->total_encode_time =
402 static_cast<double>(video_sender_info.total_encode_time_ms) /
403 rtc::kNumMillisecsPerSec;
Henrik Boström23aff9b2019-05-20 15:15:38 +0200404 outbound_video->total_encoded_bytes_target =
405 video_sender_info.total_encoded_bytes_target;
Henrik Boström9fe18342019-05-16 18:38:20 +0200406 outbound_video->total_packet_send_delay =
407 static_cast<double>(video_sender_info.total_packet_send_delay_ms) /
408 rtc::kNumMillisecsPerSec;
Henrik Boströmce33b6a2019-05-28 17:42:38 +0200409 outbound_video->quality_limitation_reason =
410 QualityLimitationReasonToRTCQualityLimitationReason(
411 video_sender_info.quality_limitation_reason);
Evan Shrubsolecc62b162019-09-09 11:26:45 +0200412 outbound_video->quality_limitation_resolution_changes =
413 video_sender_info.quality_limitation_resolution_changes;
Henrik Boström2e069262019-04-09 13:59:31 +0200414 // TODO(https://crbug.com/webrtc/10529): When info's |content_info| is
415 // optional, support the "unspecified" value.
416 if (video_sender_info.content_type == VideoContentType::SCREENSHARE)
417 outbound_video->content_type = RTCContentType::kScreenshare;
Henrik Boström6b430862019-08-16 13:09:51 +0200418 if (!video_sender_info.encoder_implementation_name.empty()) {
419 outbound_video->encoder_implementation =
420 video_sender_info.encoder_implementation_name;
421 }
hbos6ded1902016-11-01 01:50:46 -0700422}
423
Henrik Boström883eefc2019-05-27 13:40:25 +0200424std::unique_ptr<RTCRemoteInboundRtpStreamStats>
425ProduceRemoteInboundRtpStreamStatsFromReportBlockData(
426 const ReportBlockData& report_block_data,
427 cricket::MediaType media_type,
428 const RTCStatsReport& report) {
429 const auto& report_block = report_block_data.report_block();
430 // RTCStats' timestamp generally refers to when the metric was sampled, but
431 // for "remote-[outbound/inbound]-rtp" it refers to the local time when the
432 // Report Block was received.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200433 auto remote_inbound = std::make_unique<RTCRemoteInboundRtpStreamStats>(
Henrik Boström8605fbf2019-06-24 16:44:51 +0200434 RTCRemoteInboundRtpStreamStatsIdFromSourceSsrc(media_type,
435 report_block.source_ssrc),
Henrik Boström883eefc2019-05-27 13:40:25 +0200436 /*timestamp=*/report_block_data.report_block_timestamp_utc_us());
Henrik Boström8605fbf2019-06-24 16:44:51 +0200437 remote_inbound->ssrc = report_block.source_ssrc;
Henrik Boström883eefc2019-05-27 13:40:25 +0200438 remote_inbound->kind =
439 media_type == cricket::MEDIA_TYPE_AUDIO ? "audio" : "video";
440 remote_inbound->packets_lost = report_block.packets_lost;
441 remote_inbound->round_trip_time =
442 static_cast<double>(report_block_data.last_rtt_ms()) /
443 rtc::kNumMillisecsPerSec;
444
445 std::string local_id = RTCOutboundRTPStreamStatsIDFromSSRC(
446 media_type == cricket::MEDIA_TYPE_AUDIO, report_block.source_ssrc);
447 const auto* local_id_stat = report.Get(local_id);
448 if (local_id_stat) {
449 remote_inbound->local_id = local_id;
450 const auto& outbound_rtp =
451 local_id_stat->cast_to<RTCOutboundRTPStreamStats>();
452 // The RTP/RTCP transport is obtained from the
453 // RTCOutboundRtpStreamStats's transport.
454 const auto* transport_from_id = outbound_rtp.transport_id.is_defined()
455 ? report.Get(*outbound_rtp.transport_id)
456 : nullptr;
457 if (transport_from_id) {
458 const auto& transport = transport_from_id->cast_to<RTCTransportStats>();
459 // If RTP and RTCP are not multiplexed, there is a separate RTCP
460 // transport paired with the RTP transport, otherwise the same
461 // transport is used for RTCP and RTP.
462 remote_inbound->transport_id =
463 transport.rtcp_transport_stats_id.is_defined()
464 ? *transport.rtcp_transport_stats_id
465 : *outbound_rtp.transport_id;
466 }
467 // We're assuming the same codec is used on both ends. However if the
468 // codec is switched out on the fly we may have received a Report Block
469 // based on the previous codec and there is no way to tell which point in
470 // time the codec changed for the remote end.
471 const auto* codec_from_id = outbound_rtp.codec_id.is_defined()
472 ? report.Get(*outbound_rtp.codec_id)
473 : nullptr;
474 if (codec_from_id) {
475 remote_inbound->codec_id = *outbound_rtp.codec_id;
476 const auto& codec = codec_from_id->cast_to<RTCCodecStats>();
477 if (codec.clock_rate.is_defined()) {
478 // The Report Block jitter is expressed in RTP timestamp units
479 // (https://tools.ietf.org/html/rfc3550#section-6.4.1). To convert this
480 // to seconds we divide by the codec's clock rate.
481 remote_inbound->jitter =
482 static_cast<double>(report_block.jitter) / *codec.clock_rate;
483 }
484 }
485 }
486 return remote_inbound;
487}
488
hbos02ba2112016-10-28 05:14:53 -0700489void ProduceCertificateStatsFromSSLCertificateStats(
Jonas Olssona4d87372019-07-05 19:08:33 +0200490 int64_t timestamp_us,
491 const rtc::SSLCertificateStats& certificate_stats,
hbos02ba2112016-10-28 05:14:53 -0700492 RTCStatsReport* report) {
493 RTCCertificateStats* prev_certificate_stats = nullptr;
494 for (const rtc::SSLCertificateStats* s = &certificate_stats; s;
495 s = s->issuer.get()) {
hbos02d2a922016-12-21 01:29:05 -0800496 std::string certificate_stats_id =
497 RTCCertificateIDFromFingerprint(s->fingerprint);
498 // It is possible for the same certificate to show up multiple times, e.g.
499 // if local and remote side use the same certificate in a loopback call.
500 // If the report already contains stats for this certificate, skip it.
501 if (report->Get(certificate_stats_id)) {
502 RTC_DCHECK_EQ(s, &certificate_stats);
503 break;
504 }
Jonas Olssona4d87372019-07-05 19:08:33 +0200505 RTCCertificateStats* certificate_stats =
506 new RTCCertificateStats(certificate_stats_id, timestamp_us);
hbos02ba2112016-10-28 05:14:53 -0700507 certificate_stats->fingerprint = s->fingerprint;
508 certificate_stats->fingerprint_algorithm = s->fingerprint_algorithm;
509 certificate_stats->base64_certificate = s->base64_certificate;
510 if (prev_certificate_stats)
511 prev_certificate_stats->issuer_certificate_id = certificate_stats->id();
512 report->AddStats(std::unique_ptr<RTCCertificateStats>(certificate_stats));
513 prev_certificate_stats = certificate_stats;
514 }
515}
516
Jonas Olssona4d87372019-07-05 19:08:33 +0200517const std::string& ProduceIceCandidateStats(int64_t timestamp_us,
518 const cricket::Candidate& candidate,
519 bool is_local,
520 const std::string& transport_id,
521 RTCStatsReport* report) {
hbos02ba2112016-10-28 05:14:53 -0700522 const std::string& id = "RTCIceCandidate_" + candidate.id();
523 const RTCStats* stats = report->Get(id);
524 if (!stats) {
525 std::unique_ptr<RTCIceCandidateStats> candidate_stats;
526 if (is_local)
527 candidate_stats.reset(new RTCLocalIceCandidateStats(id, timestamp_us));
528 else
529 candidate_stats.reset(new RTCRemoteIceCandidateStats(id, timestamp_us));
hbosb4e426e2017-01-02 09:59:31 -0800530 candidate_stats->transport_id = transport_id;
Gary Liu37e489c2017-11-21 10:49:36 -0800531 if (is_local) {
532 candidate_stats->network_type =
533 NetworkAdapterTypeToStatsType(candidate.network_type());
Philipp Hancke95513752018-09-27 14:40:08 +0200534 if (candidate.type() == cricket::RELAY_PORT_TYPE) {
535 std::string relay_protocol = candidate.relay_protocol();
536 RTC_DCHECK(relay_protocol.compare("udp") == 0 ||
537 relay_protocol.compare("tcp") == 0 ||
538 relay_protocol.compare("tls") == 0);
539 candidate_stats->relay_protocol = relay_protocol;
540 }
Gary Liu37e489c2017-11-21 10:49:36 -0800541 } else {
542 // We don't expect to know the adapter type of remote candidates.
543 RTC_DCHECK_EQ(rtc::ADAPTER_TYPE_UNKNOWN, candidate.network_type());
544 }
hbos02ba2112016-10-28 05:14:53 -0700545 candidate_stats->ip = candidate.address().ipaddr().ToString();
546 candidate_stats->port = static_cast<int32_t>(candidate.address().port());
547 candidate_stats->protocol = candidate.protocol();
Jonas Olssona4d87372019-07-05 19:08:33 +0200548 candidate_stats->candidate_type =
549 CandidateTypeToRTCIceCandidateType(candidate.type());
hbos02ba2112016-10-28 05:14:53 -0700550 candidate_stats->priority = static_cast<int32_t>(candidate.priority());
551
552 stats = candidate_stats.get();
553 report->AddStats(std::move(candidate_stats));
554 }
555 RTC_DCHECK_EQ(stats->type(), is_local ? RTCLocalIceCandidateStats::kType
556 : RTCRemoteIceCandidateStats::kType);
557 return stats->id();
558}
559
hbos9e302742017-01-20 02:47:10 -0800560std::unique_ptr<RTCMediaStreamTrackStats>
561ProduceMediaStreamTrackStatsFromVoiceSenderInfo(
562 int64_t timestamp_us,
563 const AudioTrackInterface& audio_track,
Harald Alvestrandc72af932018-01-11 17:18:19 +0100564 const cricket::VoiceSenderInfo& voice_sender_info,
565 int attachment_id) {
hbos9e302742017-01-20 02:47:10 -0800566 std::unique_ptr<RTCMediaStreamTrackStats> audio_track_stats(
567 new RTCMediaStreamTrackStats(
Harald Alvestranda3dab842018-01-14 09:18:58 +0100568 RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(kSender,
569 attachment_id),
Harald Alvestrandc72af932018-01-11 17:18:19 +0100570 timestamp_us, RTCMediaStreamTrackKind::kAudio));
hbos9e302742017-01-20 02:47:10 -0800571 SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
572 audio_track, audio_track_stats.get());
Henrik Boström646fda02019-05-22 15:49:42 +0200573 audio_track_stats->media_source_id =
574 RTCMediaSourceStatsIDFromKindAndAttachment(cricket::MEDIA_TYPE_AUDIO,
575 attachment_id);
hbos9e302742017-01-20 02:47:10 -0800576 audio_track_stats->remote_source = false;
577 audio_track_stats->detached = false;
Ivo Creusen56d46092017-11-24 17:29:59 +0100578 if (voice_sender_info.apm_statistics.echo_return_loss) {
579 audio_track_stats->echo_return_loss =
580 *voice_sender_info.apm_statistics.echo_return_loss;
hbos9e302742017-01-20 02:47:10 -0800581 }
Ivo Creusen56d46092017-11-24 17:29:59 +0100582 if (voice_sender_info.apm_statistics.echo_return_loss_enhancement) {
583 audio_track_stats->echo_return_loss_enhancement =
584 *voice_sender_info.apm_statistics.echo_return_loss_enhancement;
hbos9e302742017-01-20 02:47:10 -0800585 }
586 return audio_track_stats;
587}
588
589std::unique_ptr<RTCMediaStreamTrackStats>
590ProduceMediaStreamTrackStatsFromVoiceReceiverInfo(
591 int64_t timestamp_us,
592 const AudioTrackInterface& audio_track,
Harald Alvestrandc72af932018-01-11 17:18:19 +0100593 const cricket::VoiceReceiverInfo& voice_receiver_info,
594 int attachment_id) {
595 // Since receiver tracks can't be reattached, we use the SSRC as
596 // an attachment identifier.
hbos9e302742017-01-20 02:47:10 -0800597 std::unique_ptr<RTCMediaStreamTrackStats> audio_track_stats(
598 new RTCMediaStreamTrackStats(
Harald Alvestranda3dab842018-01-14 09:18:58 +0100599 RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(kReceiver,
600 attachment_id),
Harald Alvestrandc72af932018-01-11 17:18:19 +0100601 timestamp_us, RTCMediaStreamTrackKind::kAudio));
hbos9e302742017-01-20 02:47:10 -0800602 SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
603 audio_track, audio_track_stats.get());
604 audio_track_stats->remote_source = true;
605 audio_track_stats->detached = false;
606 if (voice_receiver_info.audio_level >= 0) {
Jonas Olssona4d87372019-07-05 19:08:33 +0200607 audio_track_stats->audio_level =
608 DoubleAudioLevelFromIntAudioLevel(voice_receiver_info.audio_level);
hbos9e302742017-01-20 02:47:10 -0800609 }
Gustaf Ullbergb0a02072017-10-02 12:00:34 +0200610 audio_track_stats->jitter_buffer_delay =
611 voice_receiver_info.jitter_buffer_delay_seconds;
Chen Xing0acffb52019-01-15 15:46:29 +0100612 audio_track_stats->jitter_buffer_emitted_count =
613 voice_receiver_info.jitter_buffer_emitted_count;
Ivo Creusen8d8ffdb2019-04-30 09:45:21 +0200614 audio_track_stats->inserted_samples_for_deceleration =
615 voice_receiver_info.inserted_samples_for_deceleration;
616 audio_track_stats->removed_samples_for_acceleration =
617 voice_receiver_info.removed_samples_for_acceleration;
zsteine76bd3a2017-07-14 12:17:49 -0700618 audio_track_stats->total_audio_energy =
619 voice_receiver_info.total_output_energy;
Steve Anton2dbc69f2017-08-24 17:15:13 -0700620 audio_track_stats->total_samples_received =
621 voice_receiver_info.total_samples_received;
zsteine76bd3a2017-07-14 12:17:49 -0700622 audio_track_stats->total_samples_duration =
623 voice_receiver_info.total_output_duration;
Steve Anton2dbc69f2017-08-24 17:15:13 -0700624 audio_track_stats->concealed_samples = voice_receiver_info.concealed_samples;
Ivo Creusen8d8ffdb2019-04-30 09:45:21 +0200625 audio_track_stats->silent_concealed_samples =
626 voice_receiver_info.silent_concealed_samples;
Gustaf Ullberg9a2e9062017-09-18 09:28:20 +0200627 audio_track_stats->concealment_events =
628 voice_receiver_info.concealment_events;
Ruslan Burakov8af88962018-11-22 17:21:10 +0100629 audio_track_stats->jitter_buffer_flushes =
630 voice_receiver_info.jitter_buffer_flushes;
Jakob Ivarsson352ce5c2018-11-27 12:52:16 +0100631 audio_track_stats->delayed_packet_outage_samples =
632 voice_receiver_info.delayed_packet_outage_samples;
Jakob Ivarsson232b3fd2019-03-06 09:18:40 +0100633 audio_track_stats->relative_packet_arrival_delay =
634 voice_receiver_info.relative_packet_arrival_delay_seconds;
Henrik Lundin44125fa2019-04-29 17:00:46 +0200635 audio_track_stats->interruption_count =
636 voice_receiver_info.interruption_count >= 0
637 ? voice_receiver_info.interruption_count
638 : 0;
639 audio_track_stats->total_interruption_duration =
640 static_cast<double>(voice_receiver_info.total_interruption_duration_ms) /
641 rtc::kNumMillisecsPerSec;
hbos9e302742017-01-20 02:47:10 -0800642 return audio_track_stats;
643}
644
645std::unique_ptr<RTCMediaStreamTrackStats>
646ProduceMediaStreamTrackStatsFromVideoSenderInfo(
647 int64_t timestamp_us,
648 const VideoTrackInterface& video_track,
Harald Alvestrandc72af932018-01-11 17:18:19 +0100649 const cricket::VideoSenderInfo& video_sender_info,
650 int attachment_id) {
hbos9e302742017-01-20 02:47:10 -0800651 std::unique_ptr<RTCMediaStreamTrackStats> video_track_stats(
652 new RTCMediaStreamTrackStats(
Harald Alvestranda3dab842018-01-14 09:18:58 +0100653 RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(kSender,
Harald Alvestranda3dab842018-01-14 09:18:58 +0100654 attachment_id),
Harald Alvestrandc72af932018-01-11 17:18:19 +0100655 timestamp_us, RTCMediaStreamTrackKind::kVideo));
hbos9e302742017-01-20 02:47:10 -0800656 SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
657 video_track, video_track_stats.get());
Henrik Boström646fda02019-05-22 15:49:42 +0200658 video_track_stats->media_source_id =
659 RTCMediaSourceStatsIDFromKindAndAttachment(cricket::MEDIA_TYPE_VIDEO,
660 attachment_id);
hbos9e302742017-01-20 02:47:10 -0800661 video_track_stats->remote_source = false;
662 video_track_stats->detached = false;
Jonas Olssona4d87372019-07-05 19:08:33 +0200663 video_track_stats->frame_width =
664 static_cast<uint32_t>(video_sender_info.send_frame_width);
665 video_track_stats->frame_height =
666 static_cast<uint32_t>(video_sender_info.send_frame_height);
hbosfefe0762017-01-20 06:14:25 -0800667 // TODO(hbos): Will reduce this by frames dropped due to congestion control
Harald Alvestrand89061872018-01-02 14:08:34 +0100668 // when available. https://crbug.com/659137
hbosfefe0762017-01-20 06:14:25 -0800669 video_track_stats->frames_sent = video_sender_info.frames_encoded;
Ilya Nikolaevskiy70473fc2018-02-28 16:35:03 +0100670 video_track_stats->huge_frames_sent = video_sender_info.huge_frames_sent;
hbos9e302742017-01-20 02:47:10 -0800671 return video_track_stats;
672}
673
674std::unique_ptr<RTCMediaStreamTrackStats>
675ProduceMediaStreamTrackStatsFromVideoReceiverInfo(
676 int64_t timestamp_us,
677 const VideoTrackInterface& video_track,
Harald Alvestrandc72af932018-01-11 17:18:19 +0100678 const cricket::VideoReceiverInfo& video_receiver_info,
679 int attachment_id) {
hbos9e302742017-01-20 02:47:10 -0800680 std::unique_ptr<RTCMediaStreamTrackStats> video_track_stats(
681 new RTCMediaStreamTrackStats(
Harald Alvestranda3dab842018-01-14 09:18:58 +0100682 RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(kReceiver,
683
684 attachment_id),
Harald Alvestrandc72af932018-01-11 17:18:19 +0100685 timestamp_us, RTCMediaStreamTrackKind::kVideo));
hbos9e302742017-01-20 02:47:10 -0800686 SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
687 video_track, video_track_stats.get());
688 video_track_stats->remote_source = true;
689 video_track_stats->detached = false;
690 if (video_receiver_info.frame_width > 0 &&
691 video_receiver_info.frame_height > 0) {
Jonas Olssona4d87372019-07-05 19:08:33 +0200692 video_track_stats->frame_width =
693 static_cast<uint32_t>(video_receiver_info.frame_width);
694 video_track_stats->frame_height =
695 static_cast<uint32_t>(video_receiver_info.frame_height);
hbos9e302742017-01-20 02:47:10 -0800696 }
Guido Urdaneta67378412019-05-28 17:38:08 +0200697 video_track_stats->jitter_buffer_delay =
698 video_receiver_info.jitter_buffer_delay_seconds;
699 video_track_stats->jitter_buffer_emitted_count =
700 video_receiver_info.jitter_buffer_emitted_count;
hbos42f6d2f2017-01-20 03:56:50 -0800701 video_track_stats->frames_received = video_receiver_info.frames_received;
hbosf64941f2017-01-20 07:39:09 -0800702 // TODO(hbos): When we support receiving simulcast, this should be the total
703 // number of frames correctly decoded, independent of which SSRC it was
704 // received from. Since we don't support that, this is correct and is the same
Harald Alvestrand89061872018-01-02 14:08:34 +0100705 // value as "RTCInboundRTPStreamStats.framesDecoded". https://crbug.com/659137
hbosf64941f2017-01-20 07:39:09 -0800706 video_track_stats->frames_decoded = video_receiver_info.frames_decoded;
Johannes Kron0c141c52019-08-26 15:04:43 +0200707 video_track_stats->frames_dropped = video_receiver_info.frames_dropped;
Sergey Silkin02371062019-01-31 16:45:42 +0100708 video_track_stats->freeze_count = video_receiver_info.freeze_count;
709 video_track_stats->pause_count = video_receiver_info.pause_count;
710 video_track_stats->total_freezes_duration =
711 static_cast<double>(video_receiver_info.total_freezes_duration_ms) /
712 rtc::kNumMillisecsPerSec;
713 video_track_stats->total_pauses_duration =
714 static_cast<double>(video_receiver_info.total_pauses_duration_ms) /
715 rtc::kNumMillisecsPerSec;
716 video_track_stats->total_frames_duration =
717 static_cast<double>(video_receiver_info.total_frames_duration_ms) /
718 rtc::kNumMillisecsPerSec;
719 video_track_stats->sum_squared_frame_durations =
720 video_receiver_info.sum_squared_frame_durations;
721
hbos9e302742017-01-20 02:47:10 -0800722 return video_track_stats;
723}
724
Harald Alvestrand89061872018-01-02 14:08:34 +0100725void ProduceSenderMediaTrackStats(
726 int64_t timestamp_us,
727 const TrackMediaInfoMap& track_media_info_map,
Steve Anton57858b32018-02-15 15:19:50 -0800728 std::vector<rtc::scoped_refptr<RtpSenderInternal>> senders,
Harald Alvestrand89061872018-01-02 14:08:34 +0100729 RTCStatsReport* report) {
730 // This function iterates over the senders to generate outgoing track stats.
731
732 // TODO(hbos): Return stats of detached tracks. We have to perform stats
733 // gathering at the time of detachment to get accurate stats and timestamps.
734 // https://crbug.com/659137
Mirko Bonadei739baf02019-01-27 17:29:42 +0100735 for (const auto& sender : senders) {
Harald Alvestrand89061872018-01-02 14:08:34 +0100736 if (sender->media_type() == cricket::MEDIA_TYPE_AUDIO) {
737 AudioTrackInterface* track =
738 static_cast<AudioTrackInterface*>(sender->track().get());
739 if (!track)
740 continue;
Harald Alvestrandb8e12012018-01-23 15:28:16 +0100741 cricket::VoiceSenderInfo null_sender_info;
742 const cricket::VoiceSenderInfo* voice_sender_info = &null_sender_info;
743 // TODO(hta): Checking on ssrc is not proper. There should be a way
744 // to see from a sender whether it's connected or not.
745 // Related to https://crbug.com/8694 (using ssrc 0 to indicate "none")
Steve Anton57858b32018-02-15 15:19:50 -0800746 if (sender->ssrc() != 0) {
Harald Alvestrand76d29522018-01-30 14:43:29 +0100747 // When pc.close is called, sender info is discarded, so
748 // we generate zeroes instead. Bug: It should be retained.
749 // https://crbug.com/807174
Steve Anton57858b32018-02-15 15:19:50 -0800750 const cricket::VoiceSenderInfo* sender_info =
Harald Alvestrandb8e12012018-01-23 15:28:16 +0100751 track_media_info_map.GetVoiceSenderInfoBySsrc(sender->ssrc());
Harald Alvestrand76d29522018-01-30 14:43:29 +0100752 if (sender_info) {
753 voice_sender_info = sender_info;
754 } else {
755 RTC_LOG(LS_INFO)
756 << "RTCStatsCollector: No voice sender info for sender with ssrc "
757 << sender->ssrc();
758 }
Harald Alvestrandb8e12012018-01-23 15:28:16 +0100759 }
Harald Alvestrand89061872018-01-02 14:08:34 +0100760 std::unique_ptr<RTCMediaStreamTrackStats> audio_track_stats =
Harald Alvestrandc72af932018-01-11 17:18:19 +0100761 ProduceMediaStreamTrackStatsFromVoiceSenderInfo(
762 timestamp_us, *track, *voice_sender_info, sender->AttachmentId());
Harald Alvestrand89061872018-01-02 14:08:34 +0100763 report->AddStats(std::move(audio_track_stats));
764 } else if (sender->media_type() == cricket::MEDIA_TYPE_VIDEO) {
765 VideoTrackInterface* track =
766 static_cast<VideoTrackInterface*>(sender->track().get());
767 if (!track)
768 continue;
Harald Alvestrandb8e12012018-01-23 15:28:16 +0100769 cricket::VideoSenderInfo null_sender_info;
770 const cricket::VideoSenderInfo* video_sender_info = &null_sender_info;
771 // TODO(hta): Check on state not ssrc when state is available
Harald Alvestrand76d29522018-01-30 14:43:29 +0100772 // Related to https://bugs.webrtc.org/8694 (using ssrc 0 to indicate
773 // "none")
Steve Anton57858b32018-02-15 15:19:50 -0800774 if (sender->ssrc() != 0) {
Harald Alvestrand76d29522018-01-30 14:43:29 +0100775 // When pc.close is called, sender info is discarded, so
776 // we generate zeroes instead. Bug: It should be retained.
777 // https://crbug.com/807174
Steve Anton57858b32018-02-15 15:19:50 -0800778 const cricket::VideoSenderInfo* sender_info =
Harald Alvestrandb8e12012018-01-23 15:28:16 +0100779 track_media_info_map.GetVideoSenderInfoBySsrc(sender->ssrc());
Harald Alvestrand76d29522018-01-30 14:43:29 +0100780 if (sender_info) {
781 video_sender_info = sender_info;
782 } else {
783 RTC_LOG(LS_INFO) << "No video sender info for sender with ssrc "
784 << sender->ssrc();
785 }
786 }
Harald Alvestrand89061872018-01-02 14:08:34 +0100787 std::unique_ptr<RTCMediaStreamTrackStats> video_track_stats =
Harald Alvestrandc72af932018-01-11 17:18:19 +0100788 ProduceMediaStreamTrackStatsFromVideoSenderInfo(
789 timestamp_us, *track, *video_sender_info, sender->AttachmentId());
Harald Alvestrand89061872018-01-02 14:08:34 +0100790 report->AddStats(std::move(video_track_stats));
791 } else {
792 RTC_NOTREACHED();
793 }
794 }
795}
796
797void ProduceReceiverMediaTrackStats(
798 int64_t timestamp_us,
799 const TrackMediaInfoMap& track_media_info_map,
Steve Anton57858b32018-02-15 15:19:50 -0800800 std::vector<rtc::scoped_refptr<RtpReceiverInternal>> receivers,
Harald Alvestrand89061872018-01-02 14:08:34 +0100801 RTCStatsReport* report) {
802 // This function iterates over the receivers to find the remote tracks.
Mirko Bonadei739baf02019-01-27 17:29:42 +0100803 for (const auto& receiver : receivers) {
Harald Alvestrand89061872018-01-02 14:08:34 +0100804 if (receiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
805 AudioTrackInterface* track =
806 static_cast<AudioTrackInterface*>(receiver->track().get());
807 const cricket::VoiceReceiverInfo* voice_receiver_info =
808 track_media_info_map.GetVoiceReceiverInfo(*track);
809 if (!voice_receiver_info) {
810 continue;
811 }
812 std::unique_ptr<RTCMediaStreamTrackStats> audio_track_stats =
813 ProduceMediaStreamTrackStatsFromVoiceReceiverInfo(
Harald Alvestrandc72af932018-01-11 17:18:19 +0100814 timestamp_us, *track, *voice_receiver_info,
815 receiver->AttachmentId());
Harald Alvestrand89061872018-01-02 14:08:34 +0100816 report->AddStats(std::move(audio_track_stats));
817 } else if (receiver->media_type() == cricket::MEDIA_TYPE_VIDEO) {
818 VideoTrackInterface* track =
819 static_cast<VideoTrackInterface*>(receiver->track().get());
820 const cricket::VideoReceiverInfo* video_receiver_info =
821 track_media_info_map.GetVideoReceiverInfo(*track);
822 if (!video_receiver_info) {
823 continue;
824 }
825 std::unique_ptr<RTCMediaStreamTrackStats> video_track_stats =
826 ProduceMediaStreamTrackStatsFromVideoReceiverInfo(
Harald Alvestrandc72af932018-01-11 17:18:19 +0100827 timestamp_us, *track, *video_receiver_info,
828 receiver->AttachmentId());
Harald Alvestrand89061872018-01-02 14:08:34 +0100829 report->AddStats(std::move(video_track_stats));
830 } else {
831 RTC_NOTREACHED();
832 }
833 }
834}
835
Henrik Boström5b3541f2018-03-19 13:52:56 +0100836rtc::scoped_refptr<RTCStatsReport> CreateReportFilteredBySelector(
837 bool filter_by_sender_selector,
838 rtc::scoped_refptr<const RTCStatsReport> report,
839 rtc::scoped_refptr<RtpSenderInternal> sender_selector,
840 rtc::scoped_refptr<RtpReceiverInternal> receiver_selector) {
841 std::vector<std::string> rtpstream_ids;
842 if (filter_by_sender_selector) {
843 // Filter mode: RTCStatsCollector::RequestInfo::kSenderSelector
844 if (sender_selector) {
845 // Find outbound-rtp(s) of the sender, i.e. the outbound-rtp(s) that
846 // reference the sender stats.
847 // Because we do not implement sender stats, we look at outbound-rtp(s)
848 // that reference the track attachment stats for the sender instead.
849 std::string track_id =
850 RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
851 kSender, sender_selector->AttachmentId());
852 for (const auto& stats : *report) {
853 if (stats.type() != RTCOutboundRTPStreamStats::kType)
854 continue;
855 const auto& outbound_rtp = stats.cast_to<RTCOutboundRTPStreamStats>();
856 if (outbound_rtp.track_id.is_defined() &&
857 *outbound_rtp.track_id == track_id) {
858 rtpstream_ids.push_back(outbound_rtp.id());
859 }
860 }
861 }
862 } else {
863 // Filter mode: RTCStatsCollector::RequestInfo::kReceiverSelector
864 if (receiver_selector) {
865 // Find inbound-rtp(s) of the receiver, i.e. the inbound-rtp(s) that
866 // reference the receiver stats.
867 // Because we do not implement receiver stats, we look at inbound-rtp(s)
868 // that reference the track attachment stats for the receiver instead.
869 std::string track_id =
870 RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
871 kReceiver, receiver_selector->AttachmentId());
872 for (const auto& stats : *report) {
873 if (stats.type() != RTCInboundRTPStreamStats::kType)
874 continue;
875 const auto& inbound_rtp = stats.cast_to<RTCInboundRTPStreamStats>();
876 if (inbound_rtp.track_id.is_defined() &&
877 *inbound_rtp.track_id == track_id) {
878 rtpstream_ids.push_back(inbound_rtp.id());
879 }
880 }
881 }
882 }
883 if (rtpstream_ids.empty())
884 return RTCStatsReport::Create(report->timestamp_us());
885 return TakeReferencedStats(report->Copy(), rtpstream_ids);
886}
887
hboscc555c52016-10-18 12:48:31 -0700888} // namespace
889
Henrik Boström5b3541f2018-03-19 13:52:56 +0100890RTCStatsCollector::RequestInfo::RequestInfo(
891 rtc::scoped_refptr<RTCStatsCollectorCallback> callback)
892 : RequestInfo(FilterMode::kAll, std::move(callback), nullptr, nullptr) {}
893
894RTCStatsCollector::RequestInfo::RequestInfo(
895 rtc::scoped_refptr<RtpSenderInternal> selector,
896 rtc::scoped_refptr<RTCStatsCollectorCallback> callback)
897 : RequestInfo(FilterMode::kSenderSelector,
898 std::move(callback),
899 std::move(selector),
900 nullptr) {}
901
902RTCStatsCollector::RequestInfo::RequestInfo(
903 rtc::scoped_refptr<RtpReceiverInternal> selector,
904 rtc::scoped_refptr<RTCStatsCollectorCallback> callback)
905 : RequestInfo(FilterMode::kReceiverSelector,
906 std::move(callback),
907 nullptr,
908 std::move(selector)) {}
909
910RTCStatsCollector::RequestInfo::RequestInfo(
911 RTCStatsCollector::RequestInfo::FilterMode filter_mode,
912 rtc::scoped_refptr<RTCStatsCollectorCallback> callback,
913 rtc::scoped_refptr<RtpSenderInternal> sender_selector,
914 rtc::scoped_refptr<RtpReceiverInternal> receiver_selector)
915 : filter_mode_(filter_mode),
916 callback_(std::move(callback)),
917 sender_selector_(std::move(sender_selector)),
918 receiver_selector_(std::move(receiver_selector)) {
919 RTC_DCHECK(callback_);
920 RTC_DCHECK(!sender_selector_ || !receiver_selector_);
921}
922
hbosc82f2e12016-09-05 01:36:50 -0700923rtc::scoped_refptr<RTCStatsCollector> RTCStatsCollector::Create(
Steve Anton2d8609c2018-01-23 16:38:46 -0800924 PeerConnectionInternal* pc,
925 int64_t cache_lifetime_us) {
hbosc82f2e12016-09-05 01:36:50 -0700926 return rtc::scoped_refptr<RTCStatsCollector>(
927 new rtc::RefCountedObject<RTCStatsCollector>(pc, cache_lifetime_us));
928}
929
Steve Anton2d8609c2018-01-23 16:38:46 -0800930RTCStatsCollector::RTCStatsCollector(PeerConnectionInternal* pc,
hbosc82f2e12016-09-05 01:36:50 -0700931 int64_t cache_lifetime_us)
hbosd565b732016-08-30 14:04:35 -0700932 : pc_(pc),
Steve Anton978b8762017-09-29 12:15:02 -0700933 signaling_thread_(pc->signaling_thread()),
934 worker_thread_(pc->worker_thread()),
935 network_thread_(pc->network_thread()),
hbosc82f2e12016-09-05 01:36:50 -0700936 num_pending_partial_reports_(0),
937 partial_report_timestamp_us_(0),
Henrik Boström40b030e2019-02-28 09:49:31 +0100938 network_report_event_(true /* manual_reset */,
939 true /* initially_signaled */),
hbos0e6758d2016-08-31 07:57:36 -0700940 cache_timestamp_us_(0),
941 cache_lifetime_us_(cache_lifetime_us) {
hbosd565b732016-08-30 14:04:35 -0700942 RTC_DCHECK(pc_);
hbosc82f2e12016-09-05 01:36:50 -0700943 RTC_DCHECK(signaling_thread_);
944 RTC_DCHECK(worker_thread_);
945 RTC_DCHECK(network_thread_);
hbos0e6758d2016-08-31 07:57:36 -0700946 RTC_DCHECK_GE(cache_lifetime_us_, 0);
Steve Anton2d8609c2018-01-23 16:38:46 -0800947 pc_->SignalDataChannelCreated().connect(
hbos82ebe022016-11-14 01:41:09 -0800948 this, &RTCStatsCollector::OnDataChannelCreated);
hbosd565b732016-08-30 14:04:35 -0700949}
950
hbosb78306a2016-12-19 05:06:57 -0800951RTCStatsCollector::~RTCStatsCollector() {
952 RTC_DCHECK_EQ(num_pending_partial_reports_, 0);
953}
954
hbosc82f2e12016-09-05 01:36:50 -0700955void RTCStatsCollector::GetStatsReport(
956 rtc::scoped_refptr<RTCStatsCollectorCallback> callback) {
Henrik Boström5b3541f2018-03-19 13:52:56 +0100957 GetStatsReportInternal(RequestInfo(std::move(callback)));
958}
959
960void RTCStatsCollector::GetStatsReport(
961 rtc::scoped_refptr<RtpSenderInternal> selector,
962 rtc::scoped_refptr<RTCStatsCollectorCallback> callback) {
963 GetStatsReportInternal(RequestInfo(std::move(selector), std::move(callback)));
964}
965
966void RTCStatsCollector::GetStatsReport(
967 rtc::scoped_refptr<RtpReceiverInternal> selector,
968 rtc::scoped_refptr<RTCStatsCollectorCallback> callback) {
969 GetStatsReportInternal(RequestInfo(std::move(selector), std::move(callback)));
970}
971
972void RTCStatsCollector::GetStatsReportInternal(
973 RTCStatsCollector::RequestInfo request) {
hbosc82f2e12016-09-05 01:36:50 -0700974 RTC_DCHECK(signaling_thread_->IsCurrent());
Henrik Boström5b3541f2018-03-19 13:52:56 +0100975 requests_.push_back(std::move(request));
hbosc82f2e12016-09-05 01:36:50 -0700976
hbos0e6758d2016-08-31 07:57:36 -0700977 // "Now" using a monotonically increasing timer.
978 int64_t cache_now_us = rtc::TimeMicros();
979 if (cached_report_ &&
980 cache_now_us - cache_timestamp_us_ <= cache_lifetime_us_) {
Taylor Brandstetter25e022f2018-03-08 09:53:47 -0800981 // We have a fresh cached report to deliver. Deliver asynchronously, since
982 // the caller may not be expecting a synchronous callback, and it avoids
983 // reentrancy problems.
Henrik Boström5b3541f2018-03-19 13:52:56 +0100984 std::vector<RequestInfo> requests;
985 requests.swap(requests_);
Henrik Boström40b030e2019-02-28 09:49:31 +0100986 signaling_thread_->PostTask(
987 RTC_FROM_HERE, rtc::Bind(&RTCStatsCollector::DeliverCachedReport, this,
988 cached_report_, std::move(requests)));
hbosc82f2e12016-09-05 01:36:50 -0700989 } else if (!num_pending_partial_reports_) {
990 // Only start gathering stats if we're not already gathering stats. In the
991 // case of already gathering stats, |callback_| will be invoked when there
992 // are no more pending partial reports.
993
994 // "Now" using a system clock, relative to the UNIX epoch (Jan 1, 1970,
995 // UTC), in microseconds. The system clock could be modified and is not
996 // necessarily monotonically increasing.
nissecdf37a92016-09-13 23:41:47 -0700997 int64_t timestamp_us = rtc::TimeUTCMicros();
hbosc82f2e12016-09-05 01:36:50 -0700998
hbosf415f8a2017-01-02 04:28:51 -0800999 num_pending_partial_reports_ = 2;
hbosc82f2e12016-09-05 01:36:50 -07001000 partial_report_timestamp_us_ = cache_now_us;
hbosdf6075a2016-12-19 04:58:02 -08001001
Steve Anton57858b32018-02-15 15:19:50 -08001002 // Prepare |transceiver_stats_infos_| for use in
hbos84abeb12017-01-16 06:16:44 -08001003 // |ProducePartialResultsOnNetworkThread| and
1004 // |ProducePartialResultsOnSignalingThread|.
Steve Anton57858b32018-02-15 15:19:50 -08001005 transceiver_stats_infos_ = PrepareTransceiverStatsInfos_s();
Steve Anton7eca0932018-03-30 15:18:41 -07001006 // Prepare |transport_names_| for use in
1007 // |ProducePartialResultsOnNetworkThread|.
1008 transport_names_ = PrepareTransportNames_s();
Steve Anton5dfde182018-02-06 10:34:40 -08001009
stefanf79ade12017-06-02 06:44:03 -07001010 // Prepare |call_stats_| here since GetCallStats() will hop to the worker
1011 // thread.
1012 // TODO(holmer): To avoid the hop we could move BWE and BWE stats to the
1013 // network thread, where it more naturally belongs.
Steve Anton978b8762017-09-29 12:15:02 -07001014 call_stats_ = pc_->GetCallStats();
stefanf79ade12017-06-02 06:44:03 -07001015
Henrik Boström40b030e2019-02-28 09:49:31 +01001016 // Don't touch |network_report_| on the signaling thread until
1017 // ProducePartialResultsOnNetworkThread() has signaled the
1018 // |network_report_event_|.
1019 network_report_event_.Reset();
1020 network_thread_->PostTask(
1021 RTC_FROM_HERE,
hbosc82f2e12016-09-05 01:36:50 -07001022 rtc::Bind(&RTCStatsCollector::ProducePartialResultsOnNetworkThread,
Henrik Boström40b030e2019-02-28 09:49:31 +01001023 this, timestamp_us));
hbosf415f8a2017-01-02 04:28:51 -08001024 ProducePartialResultsOnSignalingThread(timestamp_us);
hbos0e6758d2016-08-31 07:57:36 -07001025 }
hbosd565b732016-08-30 14:04:35 -07001026}
1027
1028void RTCStatsCollector::ClearCachedStatsReport() {
hbosc82f2e12016-09-05 01:36:50 -07001029 RTC_DCHECK(signaling_thread_->IsCurrent());
hbosd565b732016-08-30 14:04:35 -07001030 cached_report_ = nullptr;
1031}
1032
hbosb78306a2016-12-19 05:06:57 -08001033void RTCStatsCollector::WaitForPendingRequest() {
1034 RTC_DCHECK(signaling_thread_->IsCurrent());
Henrik Boström40b030e2019-02-28 09:49:31 +01001035 // If a request is pending, blocks until the |network_report_event_| is
1036 // signaled and then delivers the result. Otherwise this is a NO-OP.
1037 MergeNetworkReport_s();
hbosb78306a2016-12-19 05:06:57 -08001038}
1039
hbosc82f2e12016-09-05 01:36:50 -07001040void RTCStatsCollector::ProducePartialResultsOnSignalingThread(
1041 int64_t timestamp_us) {
1042 RTC_DCHECK(signaling_thread_->IsCurrent());
Henrik Boström40b030e2019-02-28 09:49:31 +01001043 partial_report_ = RTCStatsReport::Create(timestamp_us);
hbosc82f2e12016-09-05 01:36:50 -07001044
Henrik Boström40b030e2019-02-28 09:49:31 +01001045 ProducePartialResultsOnSignalingThreadImpl(timestamp_us,
1046 partial_report_.get());
hbosc82f2e12016-09-05 01:36:50 -07001047
Henrik Boström40b030e2019-02-28 09:49:31 +01001048 // ProducePartialResultsOnSignalingThread() is running synchronously on the
1049 // signaling thread, so it is always the first partial result delivered on the
1050 // signaling thread. The request is not complete until MergeNetworkReport_s()
1051 // happens; we don't have to do anything here.
1052 RTC_DCHECK_GT(num_pending_partial_reports_, 1);
1053 --num_pending_partial_reports_;
1054}
1055
1056void RTCStatsCollector::ProducePartialResultsOnSignalingThreadImpl(
1057 int64_t timestamp_us,
1058 RTCStatsReport* partial_report) {
1059 RTC_DCHECK(signaling_thread_->IsCurrent());
1060 ProduceDataChannelStats_s(timestamp_us, partial_report);
1061 ProduceMediaStreamStats_s(timestamp_us, partial_report);
1062 ProduceMediaStreamTrackStats_s(timestamp_us, partial_report);
Henrik Boström646fda02019-05-22 15:49:42 +02001063 ProduceMediaSourceStats_s(timestamp_us, partial_report);
Henrik Boström40b030e2019-02-28 09:49:31 +01001064 ProducePeerConnectionStats_s(timestamp_us, partial_report);
hbosc82f2e12016-09-05 01:36:50 -07001065}
1066
hbosc82f2e12016-09-05 01:36:50 -07001067void RTCStatsCollector::ProducePartialResultsOnNetworkThread(
1068 int64_t timestamp_us) {
1069 RTC_DCHECK(network_thread_->IsCurrent());
Ivo Creusen8d8ffdb2019-04-30 09:45:21 +02001070 // Touching |network_report_| on this thread is safe by this method because
Henrik Boström40b030e2019-02-28 09:49:31 +01001071 // |network_report_event_| is reset before this method is invoked.
1072 network_report_ = RTCStatsReport::Create(timestamp_us);
hbosc82f2e12016-09-05 01:36:50 -07001073
Steve Anton5dfde182018-02-06 10:34:40 -08001074 std::map<std::string, cricket::TransportStats> transport_stats_by_name =
Steve Anton7eca0932018-03-30 15:18:41 -07001075 pc_->GetTransportStatsByNames(transport_names_);
Steve Anton5dfde182018-02-06 10:34:40 -08001076 std::map<std::string, CertificateStatsPair> transport_cert_stats =
1077 PrepareTransportCertificateStats_n(transport_stats_by_name);
1078
Henrik Boström40b030e2019-02-28 09:49:31 +01001079 ProducePartialResultsOnNetworkThreadImpl(
1080 timestamp_us, transport_stats_by_name, transport_cert_stats,
1081 network_report_.get());
Mirko Bonadeica890ee2019-02-15 21:10:40 +00001082
Henrik Boström40b030e2019-02-28 09:49:31 +01001083 // Signal that it is now safe to touch |network_report_| on the signaling
1084 // thread, and post a task to merge it into the final results.
1085 network_report_event_.Set();
1086 signaling_thread_->PostTask(
1087 RTC_FROM_HERE, rtc::Bind(&RTCStatsCollector::MergeNetworkReport_s, this));
Henrik Boström05d43c62019-02-15 10:23:08 +01001088}
1089
Henrik Boström40b030e2019-02-28 09:49:31 +01001090void RTCStatsCollector::ProducePartialResultsOnNetworkThreadImpl(
1091 int64_t timestamp_us,
1092 const std::map<std::string, cricket::TransportStats>&
1093 transport_stats_by_name,
1094 const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
1095 RTCStatsReport* partial_report) {
1096 RTC_DCHECK(network_thread_->IsCurrent());
1097 ProduceCertificateStats_n(timestamp_us, transport_cert_stats, partial_report);
1098 ProduceCodecStats_n(timestamp_us, transceiver_stats_infos_, partial_report);
1099 ProduceIceCandidateAndPairStats_n(timestamp_us, transport_stats_by_name,
1100 call_stats_, partial_report);
Henrik Boström40b030e2019-02-28 09:49:31 +01001101 ProduceTransportStats_n(timestamp_us, transport_stats_by_name,
1102 transport_cert_stats, partial_report);
Henrik Boström883eefc2019-05-27 13:40:25 +02001103 ProduceRTPStreamStats_n(timestamp_us, transceiver_stats_infos_,
1104 partial_report);
Henrik Boström40b030e2019-02-28 09:49:31 +01001105}
1106
1107void RTCStatsCollector::MergeNetworkReport_s() {
1108 RTC_DCHECK(signaling_thread_->IsCurrent());
1109 // The |network_report_event_| must be signaled for it to be safe to touch
1110 // |network_report_|. This is normally not blocking, but if
1111 // WaitForPendingRequest() is called while a request is pending, we might have
1112 // to wait until the network thread is done touching |network_report_|.
1113 network_report_event_.Wait(rtc::Event::kForever);
1114 if (!network_report_) {
1115 // Normally, MergeNetworkReport_s() is executed because it is posted from
1116 // the network thread. But if WaitForPendingRequest() is called while a
1117 // request is pending, an early call to MergeNetworkReport_s() is made,
1118 // merging the report and setting |network_report_| to null. If so, when the
1119 // previously posted MergeNetworkReport_s() is later executed, the report is
1120 // already null and nothing needs to be done here.
hbosc82f2e12016-09-05 01:36:50 -07001121 return;
1122 }
Mirko Bonadeica890ee2019-02-15 21:10:40 +00001123 RTC_DCHECK_GT(num_pending_partial_reports_, 0);
Henrik Boström40b030e2019-02-28 09:49:31 +01001124 RTC_DCHECK(partial_report_);
1125 partial_report_->TakeMembersFrom(network_report_);
1126 network_report_ = nullptr;
Mirko Bonadeica890ee2019-02-15 21:10:40 +00001127 --num_pending_partial_reports_;
Henrik Boström40b030e2019-02-28 09:49:31 +01001128 // |network_report_| is currently the only partial report collected
1129 // asynchronously, so |num_pending_partial_reports_| must now be 0 and we are
1130 // ready to deliver the result.
1131 RTC_DCHECK_EQ(num_pending_partial_reports_, 0);
1132 cache_timestamp_us_ = partial_report_timestamp_us_;
1133 cached_report_ = partial_report_;
1134 partial_report_ = nullptr;
1135 transceiver_stats_infos_.clear();
1136 // Trace WebRTC Stats when getStats is called on Javascript.
1137 // This allows access to WebRTC stats from trace logs. To enable them,
1138 // select the "webrtc_stats" category when recording traces.
1139 TRACE_EVENT_INSTANT1("webrtc_stats", "webrtc_stats", "report",
1140 cached_report_->ToJson());
Mirko Bonadeica890ee2019-02-15 21:10:40 +00001141
Henrik Boström40b030e2019-02-28 09:49:31 +01001142 // Deliver report and clear |requests_|.
1143 std::vector<RequestInfo> requests;
1144 requests.swap(requests_);
1145 DeliverCachedReport(cached_report_, std::move(requests));
hbosc82f2e12016-09-05 01:36:50 -07001146}
1147
Taylor Brandstetter25e022f2018-03-08 09:53:47 -08001148void RTCStatsCollector::DeliverCachedReport(
1149 rtc::scoped_refptr<const RTCStatsReport> cached_report,
Henrik Boström5b3541f2018-03-19 13:52:56 +01001150 std::vector<RTCStatsCollector::RequestInfo> requests) {
hbosc82f2e12016-09-05 01:36:50 -07001151 RTC_DCHECK(signaling_thread_->IsCurrent());
Henrik Boström5b3541f2018-03-19 13:52:56 +01001152 RTC_DCHECK(!requests.empty());
Taylor Brandstetter25e022f2018-03-08 09:53:47 -08001153 RTC_DCHECK(cached_report);
Taylor Brandstetter87d5a742018-03-06 09:42:25 -08001154
Henrik Boström5b3541f2018-03-19 13:52:56 +01001155 for (const RequestInfo& request : requests) {
1156 if (request.filter_mode() == RequestInfo::FilterMode::kAll) {
1157 request.callback()->OnStatsDelivered(cached_report);
1158 } else {
1159 bool filter_by_sender_selector;
1160 rtc::scoped_refptr<RtpSenderInternal> sender_selector;
1161 rtc::scoped_refptr<RtpReceiverInternal> receiver_selector;
1162 if (request.filter_mode() == RequestInfo::FilterMode::kSenderSelector) {
1163 filter_by_sender_selector = true;
1164 sender_selector = request.sender_selector();
1165 } else {
1166 RTC_DCHECK(request.filter_mode() ==
1167 RequestInfo::FilterMode::kReceiverSelector);
1168 filter_by_sender_selector = false;
1169 receiver_selector = request.receiver_selector();
1170 }
1171 request.callback()->OnStatsDelivered(CreateReportFilteredBySelector(
1172 filter_by_sender_selector, cached_report, sender_selector,
1173 receiver_selector));
1174 }
hbosc82f2e12016-09-05 01:36:50 -07001175 }
hbosd565b732016-08-30 14:04:35 -07001176}
1177
hbosdf6075a2016-12-19 04:58:02 -08001178void RTCStatsCollector::ProduceCertificateStats_n(
hbos2fa7c672016-10-24 04:00:05 -07001179 int64_t timestamp_us,
1180 const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
hbos6ab97ce2016-10-03 14:16:56 -07001181 RTCStatsReport* report) const {
hbosdf6075a2016-12-19 04:58:02 -08001182 RTC_DCHECK(network_thread_->IsCurrent());
hbos02ba2112016-10-28 05:14:53 -07001183 for (const auto& transport_cert_stats_pair : transport_cert_stats) {
1184 if (transport_cert_stats_pair.second.local) {
1185 ProduceCertificateStatsFromSSLCertificateStats(
1186 timestamp_us, *transport_cert_stats_pair.second.local.get(), report);
hbos6ab97ce2016-10-03 14:16:56 -07001187 }
hbos02ba2112016-10-28 05:14:53 -07001188 if (transport_cert_stats_pair.second.remote) {
1189 ProduceCertificateStatsFromSSLCertificateStats(
1190 timestamp_us, *transport_cert_stats_pair.second.remote.get(), report);
hbos6ab97ce2016-10-03 14:16:56 -07001191 }
1192 }
1193}
1194
hbosdf6075a2016-12-19 04:58:02 -08001195void RTCStatsCollector::ProduceCodecStats_n(
Steve Anton57858b32018-02-15 15:19:50 -08001196 int64_t timestamp_us,
1197 const std::vector<RtpTransceiverStatsInfo>& transceiver_stats_infos,
hbos0adb8282016-11-23 02:32:06 -08001198 RTCStatsReport* report) const {
hbosdf6075a2016-12-19 04:58:02 -08001199 RTC_DCHECK(network_thread_->IsCurrent());
Steve Anton57858b32018-02-15 15:19:50 -08001200 for (const auto& stats : transceiver_stats_infos) {
1201 if (!stats.mid) {
1202 continue;
hbos0adb8282016-11-23 02:32:06 -08001203 }
Steve Anton57858b32018-02-15 15:19:50 -08001204 const cricket::VoiceMediaInfo* voice_media_info =
1205 stats.track_media_info_map->voice_media_info();
1206 const cricket::VideoMediaInfo* video_media_info =
1207 stats.track_media_info_map->video_media_info();
1208 // Audio
1209 if (voice_media_info) {
1210 // Inbound
1211 for (const auto& pair : voice_media_info->receive_codecs) {
1212 report->AddStats(CodecStatsFromRtpCodecParameters(
1213 timestamp_us, *stats.mid, true, pair.second));
1214 }
1215 // Outbound
1216 for (const auto& pair : voice_media_info->send_codecs) {
1217 report->AddStats(CodecStatsFromRtpCodecParameters(
1218 timestamp_us, *stats.mid, false, pair.second));
1219 }
Guido Urdanetaee2388f2018-02-15 16:36:19 +00001220 }
Steve Anton57858b32018-02-15 15:19:50 -08001221 // Video
1222 if (video_media_info) {
1223 // Inbound
1224 for (const auto& pair : video_media_info->receive_codecs) {
1225 report->AddStats(CodecStatsFromRtpCodecParameters(
1226 timestamp_us, *stats.mid, true, pair.second));
1227 }
1228 // Outbound
1229 for (const auto& pair : video_media_info->send_codecs) {
1230 report->AddStats(CodecStatsFromRtpCodecParameters(
1231 timestamp_us, *stats.mid, false, pair.second));
1232 }
hbos0adb8282016-11-23 02:32:06 -08001233 }
1234 }
1235}
1236
hboscc555c52016-10-18 12:48:31 -07001237void RTCStatsCollector::ProduceDataChannelStats_s(
Jonas Olssona4d87372019-07-05 19:08:33 +02001238 int64_t timestamp_us,
1239 RTCStatsReport* report) const {
hboscc555c52016-10-18 12:48:31 -07001240 RTC_DCHECK(signaling_thread_->IsCurrent());
1241 for (const rtc::scoped_refptr<DataChannel>& data_channel :
1242 pc_->sctp_data_channels()) {
1243 std::unique_ptr<RTCDataChannelStats> data_channel_stats(
1244 new RTCDataChannelStats(
Harald Alvestrand928e7a32019-07-31 07:16:45 -04001245 "RTCDataChannel_" + rtc::ToString(data_channel->internal_id()),
hboscc555c52016-10-18 12:48:31 -07001246 timestamp_us));
1247 data_channel_stats->label = data_channel->label();
1248 data_channel_stats->protocol = data_channel->protocol();
1249 data_channel_stats->datachannelid = data_channel->id();
1250 data_channel_stats->state =
1251 DataStateToRTCDataChannelState(data_channel->state());
1252 data_channel_stats->messages_sent = data_channel->messages_sent();
1253 data_channel_stats->bytes_sent = data_channel->bytes_sent();
1254 data_channel_stats->messages_received = data_channel->messages_received();
1255 data_channel_stats->bytes_received = data_channel->bytes_received();
1256 report->AddStats(std::move(data_channel_stats));
1257 }
1258}
1259
hbosdf6075a2016-12-19 04:58:02 -08001260void RTCStatsCollector::ProduceIceCandidateAndPairStats_n(
stefanf79ade12017-06-02 06:44:03 -07001261 int64_t timestamp_us,
Steve Anton5dfde182018-02-06 10:34:40 -08001262 const std::map<std::string, cricket::TransportStats>&
1263 transport_stats_by_name,
stefanf79ade12017-06-02 06:44:03 -07001264 const Call::Stats& call_stats,
1265 RTCStatsReport* report) const {
hbosdf6075a2016-12-19 04:58:02 -08001266 RTC_DCHECK(network_thread_->IsCurrent());
Steve Anton5dfde182018-02-06 10:34:40 -08001267 for (const auto& entry : transport_stats_by_name) {
1268 const std::string& transport_name = entry.first;
1269 const cricket::TransportStats& transport_stats = entry.second;
1270 for (const auto& channel_stats : transport_stats.channel_stats) {
hbos0583b282016-11-30 01:50:14 -08001271 std::string transport_id = RTCTransportStatsIDFromTransportChannel(
Steve Anton5dfde182018-02-06 10:34:40 -08001272 transport_name, channel_stats.component);
hbosc47a0c32016-10-11 14:54:49 -07001273 for (const cricket::ConnectionInfo& info :
Jonas Oreland149dc722019-08-28 08:10:27 +02001274 channel_stats.ice_transport_stats.connection_infos) {
hbosc47a0c32016-10-11 14:54:49 -07001275 std::unique_ptr<RTCIceCandidatePairStats> candidate_pair_stats(
hbos2fa7c672016-10-24 04:00:05 -07001276 new RTCIceCandidatePairStats(
1277 RTCIceCandidatePairStatsIDFromConnectionInfo(info),
1278 timestamp_us));
hbosc47a0c32016-10-11 14:54:49 -07001279
hbos0583b282016-11-30 01:50:14 -08001280 candidate_pair_stats->transport_id = transport_id;
hbosab9f6e42016-10-07 02:18:47 -07001281 // TODO(hbos): There could be other candidates that are not paired with
1282 // anything. We don't have a complete list. Local candidates come from
1283 // Port objects, and prflx candidates (both local and remote) are only
Harald Alvestrand89061872018-01-02 14:08:34 +01001284 // stored in candidate pairs. https://crbug.com/632723
hbos02ba2112016-10-28 05:14:53 -07001285 candidate_pair_stats->local_candidate_id = ProduceIceCandidateStats(
hbosb4e426e2017-01-02 09:59:31 -08001286 timestamp_us, info.local_candidate, true, transport_id, report);
hbos02ba2112016-10-28 05:14:53 -07001287 candidate_pair_stats->remote_candidate_id = ProduceIceCandidateStats(
hbosb4e426e2017-01-02 09:59:31 -08001288 timestamp_us, info.remote_candidate, false, transport_id, report);
hbos06495bc2017-01-02 08:08:18 -08001289 candidate_pair_stats->state =
1290 IceCandidatePairStateToRTCStatsIceCandidatePairState(info.state);
1291 candidate_pair_stats->priority = info.priority;
hbos92eaec62017-02-27 01:38:08 -08001292 candidate_pair_stats->nominated = info.nominated;
hbosc47a0c32016-10-11 14:54:49 -07001293 // TODO(hbos): This writable is different than the spec. It goes to
1294 // false after a certain amount of time without a response passes.
Harald Alvestrand89061872018-01-02 14:08:34 +01001295 // https://crbug.com/633550
hbosc47a0c32016-10-11 14:54:49 -07001296 candidate_pair_stats->writable = info.writable;
hbosc47a0c32016-10-11 14:54:49 -07001297 candidate_pair_stats->bytes_sent =
1298 static_cast<uint64_t>(info.sent_total_bytes);
1299 candidate_pair_stats->bytes_received =
1300 static_cast<uint64_t>(info.recv_total_bytes);
hbosbf8d3e52017-02-28 06:34:47 -08001301 candidate_pair_stats->total_round_trip_time =
1302 static_cast<double>(info.total_round_trip_time_ms) /
1303 rtc::kNumMillisecsPerSec;
1304 if (info.current_round_trip_time_ms) {
1305 candidate_pair_stats->current_round_trip_time =
1306 static_cast<double>(*info.current_round_trip_time_ms) /
1307 rtc::kNumMillisecsPerSec;
1308 }
stefanf79ade12017-06-02 06:44:03 -07001309 if (info.best_connection) {
hbos338f78a2017-02-07 06:41:21 -08001310 // The bandwidth estimations we have are for the selected candidate
1311 // pair ("info.best_connection").
stefanf79ade12017-06-02 06:44:03 -07001312 RTC_DCHECK_GE(call_stats.send_bandwidth_bps, 0);
1313 RTC_DCHECK_GE(call_stats.recv_bandwidth_bps, 0);
1314 if (call_stats.send_bandwidth_bps > 0) {
hbos338f78a2017-02-07 06:41:21 -08001315 candidate_pair_stats->available_outgoing_bitrate =
stefanf79ade12017-06-02 06:44:03 -07001316 static_cast<double>(call_stats.send_bandwidth_bps);
hbos338f78a2017-02-07 06:41:21 -08001317 }
stefanf79ade12017-06-02 06:44:03 -07001318 if (call_stats.recv_bandwidth_bps > 0) {
hbos338f78a2017-02-07 06:41:21 -08001319 candidate_pair_stats->available_incoming_bitrate =
stefanf79ade12017-06-02 06:44:03 -07001320 static_cast<double>(call_stats.recv_bandwidth_bps);
hbos338f78a2017-02-07 06:41:21 -08001321 }
1322 }
hbosd82f5122016-12-09 04:12:39 -08001323 candidate_pair_stats->requests_received =
1324 static_cast<uint64_t>(info.recv_ping_requests);
hbose448dd52016-12-12 01:22:53 -08001325 candidate_pair_stats->requests_sent = static_cast<uint64_t>(
1326 info.sent_ping_requests_before_first_response);
hbosc47a0c32016-10-11 14:54:49 -07001327 candidate_pair_stats->responses_received =
1328 static_cast<uint64_t>(info.recv_ping_responses);
1329 candidate_pair_stats->responses_sent =
1330 static_cast<uint64_t>(info.sent_ping_responses);
hbose448dd52016-12-12 01:22:53 -08001331 RTC_DCHECK_GE(info.sent_ping_requests_total,
1332 info.sent_ping_requests_before_first_response);
1333 candidate_pair_stats->consent_requests_sent = static_cast<uint64_t>(
1334 info.sent_ping_requests_total -
1335 info.sent_ping_requests_before_first_response);
hbosc47a0c32016-10-11 14:54:49 -07001336
1337 report->AddStats(std::move(candidate_pair_stats));
hbosab9f6e42016-10-07 02:18:47 -07001338 }
1339 }
1340 }
1341}
1342
Steve Anton57858b32018-02-15 15:19:50 -08001343void RTCStatsCollector::ProduceMediaStreamStats_s(
1344 int64_t timestamp_us,
1345 RTCStatsReport* report) const {
hbos09bc1282016-11-08 06:29:22 -08001346 RTC_DCHECK(signaling_thread_->IsCurrent());
Steve Anton57858b32018-02-15 15:19:50 -08001347
1348 std::map<std::string, std::vector<std::string>> track_ids;
1349
1350 for (const auto& stats : transceiver_stats_infos_) {
Mirko Bonadei739baf02019-01-27 17:29:42 +01001351 for (const auto& sender : stats.transceiver->senders()) {
Steve Anton57858b32018-02-15 15:19:50 -08001352 std::string track_id =
1353 RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
1354 kSender, sender->internal()->AttachmentId());
1355 for (auto& stream_id : sender->stream_ids()) {
1356 track_ids[stream_id].push_back(track_id);
1357 }
1358 }
Mirko Bonadei739baf02019-01-27 17:29:42 +01001359 for (const auto& receiver : stats.transceiver->receivers()) {
Steve Anton57858b32018-02-15 15:19:50 -08001360 std::string track_id =
1361 RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
1362 kReceiver, receiver->internal()->AttachmentId());
1363 for (auto& stream : receiver->streams()) {
Seth Hampson13b8bad2018-03-13 16:05:28 -07001364 track_ids[stream->id()].push_back(track_id);
Steve Anton57858b32018-02-15 15:19:50 -08001365 }
1366 }
1367 }
1368
1369 // Build stats for each stream ID known.
1370 for (auto& it : track_ids) {
1371 std::unique_ptr<RTCMediaStreamStats> stream_stats(
1372 new RTCMediaStreamStats("RTCMediaStream_" + it.first, timestamp_us));
1373 stream_stats->stream_identifier = it.first;
1374 stream_stats->track_ids = it.second;
1375 report->AddStats(std::move(stream_stats));
1376 }
1377}
1378
1379void RTCStatsCollector::ProduceMediaStreamTrackStats_s(
1380 int64_t timestamp_us,
1381 RTCStatsReport* report) const {
1382 RTC_DCHECK(signaling_thread_->IsCurrent());
1383 for (const RtpTransceiverStatsInfo& stats : transceiver_stats_infos_) {
1384 std::vector<rtc::scoped_refptr<RtpSenderInternal>> senders;
Mirko Bonadei739baf02019-01-27 17:29:42 +01001385 for (const auto& sender : stats.transceiver->senders()) {
Steve Anton57858b32018-02-15 15:19:50 -08001386 senders.push_back(sender->internal());
1387 }
1388 ProduceSenderMediaTrackStats(timestamp_us, *stats.track_media_info_map,
1389 senders, report);
1390
1391 std::vector<rtc::scoped_refptr<RtpReceiverInternal>> receivers;
Mirko Bonadei739baf02019-01-27 17:29:42 +01001392 for (const auto& receiver : stats.transceiver->receivers()) {
Steve Anton57858b32018-02-15 15:19:50 -08001393 receivers.push_back(receiver->internal());
1394 }
1395 ProduceReceiverMediaTrackStats(timestamp_us, *stats.track_media_info_map,
1396 receivers, report);
1397 }
hbos09bc1282016-11-08 06:29:22 -08001398}
1399
Henrik Boström646fda02019-05-22 15:49:42 +02001400void RTCStatsCollector::ProduceMediaSourceStats_s(
1401 int64_t timestamp_us,
1402 RTCStatsReport* report) const {
1403 RTC_DCHECK(signaling_thread_->IsCurrent());
1404 for (const RtpTransceiverStatsInfo& transceiver_stats_info :
1405 transceiver_stats_infos_) {
1406 const auto& track_media_info_map =
1407 transceiver_stats_info.track_media_info_map;
1408 for (const auto& sender : transceiver_stats_info.transceiver->senders()) {
1409 const auto& sender_internal = sender->internal();
1410 const auto& track = sender_internal->track();
1411 if (!track)
1412 continue;
Henrik Boströmd2c336f2019-07-03 17:11:10 +02001413 // TODO(https://crbug.com/webrtc/10771): The same track could be attached
1414 // to multiple senders which should result in multiple senders referencing
1415 // the same media-source stats. When all media source related metrics are
1416 // moved to the track's source (e.g. input frame rate is moved from
1417 // cricket::VideoSenderInfo to VideoTrackSourceInterface::Stats and audio
1418 // levels are moved to the corresponding audio track/source object), don't
1419 // create separate media source stats objects on a per-attachment basis.
Henrik Boström646fda02019-05-22 15:49:42 +02001420 std::unique_ptr<RTCMediaSourceStats> media_source_stats;
1421 if (track->kind() == MediaStreamTrackInterface::kAudioKind) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001422 auto audio_source_stats = std::make_unique<RTCAudioSourceStats>(
Henrik Boström646fda02019-05-22 15:49:42 +02001423 RTCMediaSourceStatsIDFromKindAndAttachment(
1424 cricket::MEDIA_TYPE_AUDIO, sender_internal->AttachmentId()),
1425 timestamp_us);
Henrik Boströmd2c336f2019-07-03 17:11:10 +02001426 // TODO(https://crbug.com/webrtc/10771): We shouldn't need to have an
1427 // SSRC assigned (there shouldn't need to exist a send-stream, created
1428 // by an O/A exchange) in order to read audio media-source stats.
1429 // TODO(https://crbug.com/webrtc/8694): SSRC 0 shouldn't be a magic
1430 // value indicating no SSRC.
1431 if (sender_internal->ssrc() != 0) {
1432 auto* voice_sender_info =
1433 track_media_info_map->GetVoiceSenderInfoBySsrc(
1434 sender_internal->ssrc());
1435 if (voice_sender_info) {
1436 audio_source_stats->audio_level = DoubleAudioLevelFromIntAudioLevel(
1437 voice_sender_info->audio_level);
1438 audio_source_stats->total_audio_energy =
1439 voice_sender_info->total_input_energy;
1440 audio_source_stats->total_samples_duration =
1441 voice_sender_info->total_input_duration;
1442 }
1443 }
1444 media_source_stats = std::move(audio_source_stats);
Henrik Boström646fda02019-05-22 15:49:42 +02001445 } else {
1446 RTC_DCHECK_EQ(MediaStreamTrackInterface::kVideoKind, track->kind());
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001447 auto video_source_stats = std::make_unique<RTCVideoSourceStats>(
Henrik Boström646fda02019-05-22 15:49:42 +02001448 RTCMediaSourceStatsIDFromKindAndAttachment(
1449 cricket::MEDIA_TYPE_VIDEO, sender_internal->AttachmentId()),
1450 timestamp_us);
1451 auto* video_track = static_cast<VideoTrackInterface*>(track.get());
1452 auto* video_source = video_track->GetSource();
1453 VideoTrackSourceInterface::Stats source_stats;
1454 if (video_source && video_source->GetStats(&source_stats)) {
1455 video_source_stats->width = source_stats.input_width;
1456 video_source_stats->height = source_stats.input_height;
1457 }
Henrik Boströmd2c336f2019-07-03 17:11:10 +02001458 // TODO(https://crbug.com/webrtc/10771): We shouldn't need to have an
1459 // SSRC assigned (there shouldn't need to exist a send-stream, created
1460 // by an O/A exchange) in order to get framesPerSecond.
1461 // TODO(https://crbug.com/webrtc/8694): SSRC 0 shouldn't be a magic
1462 // value indicating no SSRC.
Henrik Boström646fda02019-05-22 15:49:42 +02001463 if (sender_internal->ssrc() != 0) {
Henrik Boströmd2c336f2019-07-03 17:11:10 +02001464 auto* video_sender_info =
1465 track_media_info_map->GetVideoSenderInfoBySsrc(
1466 sender_internal->ssrc());
1467 if (video_sender_info) {
Henrik Boström646fda02019-05-22 15:49:42 +02001468 video_source_stats->frames_per_second =
Henrik Boströmd2c336f2019-07-03 17:11:10 +02001469 video_sender_info->framerate_input;
Henrik Boström646fda02019-05-22 15:49:42 +02001470 }
1471 }
1472 media_source_stats = std::move(video_source_stats);
1473 }
1474 media_source_stats->track_identifier = track->id();
1475 media_source_stats->kind = track->kind();
1476 report->AddStats(std::move(media_source_stats));
1477 }
1478 }
1479}
1480
hbos6ab97ce2016-10-03 14:16:56 -07001481void RTCStatsCollector::ProducePeerConnectionStats_s(
Jonas Olssona4d87372019-07-05 19:08:33 +02001482 int64_t timestamp_us,
1483 RTCStatsReport* report) const {
hbosc82f2e12016-09-05 01:36:50 -07001484 RTC_DCHECK(signaling_thread_->IsCurrent());
hbosd565b732016-08-30 14:04:35 -07001485 std::unique_ptr<RTCPeerConnectionStats> stats(
Jonas Olssona4d87372019-07-05 19:08:33 +02001486 new RTCPeerConnectionStats("RTCPeerConnection", timestamp_us));
hbos82ebe022016-11-14 01:41:09 -08001487 stats->data_channels_opened = internal_record_.data_channels_opened;
1488 stats->data_channels_closed = internal_record_.data_channels_closed;
hbos6ab97ce2016-10-03 14:16:56 -07001489 report->AddStats(std::move(stats));
hbosd565b732016-08-30 14:04:35 -07001490}
1491
hbosdf6075a2016-12-19 04:58:02 -08001492void RTCStatsCollector::ProduceRTPStreamStats_n(
Steve Anton593e3252017-12-15 11:44:48 -08001493 int64_t timestamp_us,
Steve Anton57858b32018-02-15 15:19:50 -08001494 const std::vector<RtpTransceiverStatsInfo>& transceiver_stats_infos,
hbos84abeb12017-01-16 06:16:44 -08001495 RTCStatsReport* report) const {
hbosdf6075a2016-12-19 04:58:02 -08001496 RTC_DCHECK(network_thread_->IsCurrent());
hbos6ded1902016-11-01 01:50:46 -07001497
Steve Anton57858b32018-02-15 15:19:50 -08001498 for (const RtpTransceiverStatsInfo& stats : transceiver_stats_infos) {
1499 if (stats.media_type == cricket::MEDIA_TYPE_AUDIO) {
1500 ProduceAudioRTPStreamStats_n(timestamp_us, stats, report);
1501 } else if (stats.media_type == cricket::MEDIA_TYPE_VIDEO) {
1502 ProduceVideoRTPStreamStats_n(timestamp_us, stats, report);
1503 } else {
1504 RTC_NOTREACHED();
Guido Urdanetaee2388f2018-02-15 16:36:19 +00001505 }
Steve Anton56bae8d2018-02-14 16:07:42 -08001506 }
Steve Anton57858b32018-02-15 15:19:50 -08001507}
1508
1509void RTCStatsCollector::ProduceAudioRTPStreamStats_n(
1510 int64_t timestamp_us,
1511 const RtpTransceiverStatsInfo& stats,
1512 RTCStatsReport* report) const {
1513 if (!stats.mid || !stats.transport_name) {
1514 return;
1515 }
1516 RTC_DCHECK(stats.track_media_info_map);
1517 const TrackMediaInfoMap& track_media_info_map = *stats.track_media_info_map;
1518 RTC_DCHECK(track_media_info_map.voice_media_info());
1519 std::string mid = *stats.mid;
1520 std::string transport_id = RTCTransportStatsIDFromTransportChannel(
1521 *stats.transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
1522 // Inbound
1523 for (const cricket::VoiceReceiverInfo& voice_receiver_info :
1524 track_media_info_map.voice_media_info()->receivers) {
1525 if (!voice_receiver_info.connected())
1526 continue;
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001527 auto inbound_audio = std::make_unique<RTCInboundRTPStreamStats>(
Steve Anton57858b32018-02-15 15:19:50 -08001528 RTCInboundRTPStreamStatsIDFromSSRC(true, voice_receiver_info.ssrc()),
1529 timestamp_us);
1530 SetInboundRTPStreamStatsFromVoiceReceiverInfo(mid, voice_receiver_info,
1531 inbound_audio.get());
1532 // TODO(hta): This lookup should look for the sender, not the track.
1533 rtc::scoped_refptr<AudioTrackInterface> audio_track =
1534 track_media_info_map.GetAudioTrack(voice_receiver_info);
1535 if (audio_track) {
1536 inbound_audio->track_id =
1537 RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
1538 kReceiver,
1539 track_media_info_map.GetAttachmentIdByTrack(audio_track).value());
hbos6ded1902016-11-01 01:50:46 -07001540 }
Steve Anton57858b32018-02-15 15:19:50 -08001541 inbound_audio->transport_id = transport_id;
1542 report->AddStats(std::move(inbound_audio));
1543 }
1544 // Outbound
1545 for (const cricket::VoiceSenderInfo& voice_sender_info :
1546 track_media_info_map.voice_media_info()->senders) {
1547 if (!voice_sender_info.connected())
1548 continue;
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001549 auto outbound_audio = std::make_unique<RTCOutboundRTPStreamStats>(
Steve Anton57858b32018-02-15 15:19:50 -08001550 RTCOutboundRTPStreamStatsIDFromSSRC(true, voice_sender_info.ssrc()),
1551 timestamp_us);
1552 SetOutboundRTPStreamStatsFromVoiceSenderInfo(mid, voice_sender_info,
1553 outbound_audio.get());
1554 rtc::scoped_refptr<AudioTrackInterface> audio_track =
1555 track_media_info_map.GetAudioTrack(voice_sender_info);
1556 if (audio_track) {
Henrik Boström646fda02019-05-22 15:49:42 +02001557 int attachment_id =
1558 track_media_info_map.GetAttachmentIdByTrack(audio_track).value();
Steve Anton57858b32018-02-15 15:19:50 -08001559 outbound_audio->track_id =
Henrik Boström646fda02019-05-22 15:49:42 +02001560 RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(kSender,
1561 attachment_id);
1562 outbound_audio->media_source_id =
1563 RTCMediaSourceStatsIDFromKindAndAttachment(cricket::MEDIA_TYPE_AUDIO,
1564 attachment_id);
Steve Anton56bae8d2018-02-14 16:07:42 -08001565 }
Steve Anton57858b32018-02-15 15:19:50 -08001566 outbound_audio->transport_id = transport_id;
1567 report->AddStats(std::move(outbound_audio));
1568 }
Henrik Boström883eefc2019-05-27 13:40:25 +02001569 // Remote-inbound
1570 // These are Report Block-based, information sent from the remote endpoint,
1571 // providing metrics about our Outbound streams. We take advantage of the fact
1572 // that RTCOutboundRtpStreamStats, RTCCodecStats and RTCTransport have already
1573 // been added to the report.
1574 for (const cricket::VoiceSenderInfo& voice_sender_info :
1575 track_media_info_map.voice_media_info()->senders) {
1576 for (const auto& report_block_data : voice_sender_info.report_block_datas) {
1577 report->AddStats(ProduceRemoteInboundRtpStreamStatsFromReportBlockData(
1578 report_block_data, cricket::MEDIA_TYPE_AUDIO, *report));
1579 }
1580 }
Steve Anton57858b32018-02-15 15:19:50 -08001581}
1582
1583void RTCStatsCollector::ProduceVideoRTPStreamStats_n(
1584 int64_t timestamp_us,
1585 const RtpTransceiverStatsInfo& stats,
1586 RTCStatsReport* report) const {
1587 if (!stats.mid || !stats.transport_name) {
1588 return;
1589 }
1590 RTC_DCHECK(stats.track_media_info_map);
1591 const TrackMediaInfoMap& track_media_info_map = *stats.track_media_info_map;
1592 RTC_DCHECK(track_media_info_map.video_media_info());
1593 std::string mid = *stats.mid;
1594 std::string transport_id = RTCTransportStatsIDFromTransportChannel(
1595 *stats.transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
1596 // Inbound
1597 for (const cricket::VideoReceiverInfo& video_receiver_info :
1598 track_media_info_map.video_media_info()->receivers) {
1599 if (!video_receiver_info.connected())
1600 continue;
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001601 auto inbound_video = std::make_unique<RTCInboundRTPStreamStats>(
Steve Anton57858b32018-02-15 15:19:50 -08001602 RTCInboundRTPStreamStatsIDFromSSRC(false, video_receiver_info.ssrc()),
1603 timestamp_us);
1604 SetInboundRTPStreamStatsFromVideoReceiverInfo(mid, video_receiver_info,
1605 inbound_video.get());
1606 rtc::scoped_refptr<VideoTrackInterface> video_track =
1607 track_media_info_map.GetVideoTrack(video_receiver_info);
1608 if (video_track) {
1609 inbound_video->track_id =
1610 RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
1611 kReceiver,
1612 track_media_info_map.GetAttachmentIdByTrack(video_track).value());
1613 }
1614 inbound_video->transport_id = transport_id;
1615 report->AddStats(std::move(inbound_video));
1616 }
1617 // Outbound
1618 for (const cricket::VideoSenderInfo& video_sender_info :
1619 track_media_info_map.video_media_info()->senders) {
1620 if (!video_sender_info.connected())
1621 continue;
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001622 auto outbound_video = std::make_unique<RTCOutboundRTPStreamStats>(
Steve Anton57858b32018-02-15 15:19:50 -08001623 RTCOutboundRTPStreamStatsIDFromSSRC(false, video_sender_info.ssrc()),
1624 timestamp_us);
1625 SetOutboundRTPStreamStatsFromVideoSenderInfo(mid, video_sender_info,
1626 outbound_video.get());
1627 rtc::scoped_refptr<VideoTrackInterface> video_track =
1628 track_media_info_map.GetVideoTrack(video_sender_info);
1629 if (video_track) {
Henrik Boström646fda02019-05-22 15:49:42 +02001630 int attachment_id =
1631 track_media_info_map.GetAttachmentIdByTrack(video_track).value();
Steve Anton57858b32018-02-15 15:19:50 -08001632 outbound_video->track_id =
Henrik Boström646fda02019-05-22 15:49:42 +02001633 RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(kSender,
1634 attachment_id);
1635 outbound_video->media_source_id =
1636 RTCMediaSourceStatsIDFromKindAndAttachment(cricket::MEDIA_TYPE_VIDEO,
1637 attachment_id);
Steve Anton57858b32018-02-15 15:19:50 -08001638 }
1639 outbound_video->transport_id = transport_id;
1640 report->AddStats(std::move(outbound_video));
hbos6ded1902016-11-01 01:50:46 -07001641 }
Henrik Boström883eefc2019-05-27 13:40:25 +02001642 // Remote-inbound
1643 // These are Report Block-based, information sent from the remote endpoint,
1644 // providing metrics about our Outbound streams. We take advantage of the fact
1645 // that RTCOutboundRtpStreamStats, RTCCodecStats and RTCTransport have already
1646 // been added to the report.
1647 for (const cricket::VideoSenderInfo& video_sender_info :
1648 track_media_info_map.video_media_info()->senders) {
1649 for (const auto& report_block_data : video_sender_info.report_block_datas) {
1650 report->AddStats(ProduceRemoteInboundRtpStreamStatsFromReportBlockData(
1651 report_block_data, cricket::MEDIA_TYPE_VIDEO, *report));
1652 }
1653 }
hbos6ded1902016-11-01 01:50:46 -07001654}
1655
hbosdf6075a2016-12-19 04:58:02 -08001656void RTCStatsCollector::ProduceTransportStats_n(
Steve Anton5dfde182018-02-06 10:34:40 -08001657 int64_t timestamp_us,
1658 const std::map<std::string, cricket::TransportStats>&
1659 transport_stats_by_name,
hbos2fa7c672016-10-24 04:00:05 -07001660 const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
1661 RTCStatsReport* report) const {
hbosdf6075a2016-12-19 04:58:02 -08001662 RTC_DCHECK(network_thread_->IsCurrent());
Steve Anton5dfde182018-02-06 10:34:40 -08001663 for (const auto& entry : transport_stats_by_name) {
1664 const std::string& transport_name = entry.first;
1665 const cricket::TransportStats& transport_stats = entry.second;
1666
hbos2fa7c672016-10-24 04:00:05 -07001667 // Get reference to RTCP channel, if it exists.
1668 std::string rtcp_transport_stats_id;
Steve Anton5dfde182018-02-06 10:34:40 -08001669 for (const cricket::TransportChannelStats& channel_stats :
1670 transport_stats.channel_stats) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001671 if (channel_stats.component == cricket::ICE_CANDIDATE_COMPONENT_RTCP) {
hbos2fa7c672016-10-24 04:00:05 -07001672 rtcp_transport_stats_id = RTCTransportStatsIDFromTransportChannel(
Steve Anton5dfde182018-02-06 10:34:40 -08001673 transport_name, channel_stats.component);
hbos2fa7c672016-10-24 04:00:05 -07001674 break;
1675 }
1676 }
1677
1678 // Get reference to local and remote certificates of this transport, if they
1679 // exist.
Steve Anton5dfde182018-02-06 10:34:40 -08001680 const auto& certificate_stats_it =
1681 transport_cert_stats.find(transport_name);
hbos2fa7c672016-10-24 04:00:05 -07001682 RTC_DCHECK(certificate_stats_it != transport_cert_stats.cend());
1683 std::string local_certificate_id;
1684 if (certificate_stats_it->second.local) {
1685 local_certificate_id = RTCCertificateIDFromFingerprint(
1686 certificate_stats_it->second.local->fingerprint);
1687 }
1688 std::string remote_certificate_id;
1689 if (certificate_stats_it->second.remote) {
1690 remote_certificate_id = RTCCertificateIDFromFingerprint(
1691 certificate_stats_it->second.remote->fingerprint);
1692 }
1693
1694 // There is one transport stats for each channel.
Steve Anton5dfde182018-02-06 10:34:40 -08001695 for (const cricket::TransportChannelStats& channel_stats :
1696 transport_stats.channel_stats) {
hbos2fa7c672016-10-24 04:00:05 -07001697 std::unique_ptr<RTCTransportStats> transport_stats(
Steve Anton5dfde182018-02-06 10:34:40 -08001698 new RTCTransportStats(RTCTransportStatsIDFromTransportChannel(
1699 transport_name, channel_stats.component),
1700 timestamp_us));
hbos2fa7c672016-10-24 04:00:05 -07001701 transport_stats->bytes_sent = 0;
1702 transport_stats->bytes_received = 0;
Jonas Olssona4d87372019-07-05 19:08:33 +02001703 transport_stats->dtls_state =
1704 DtlsTransportStateToRTCDtlsTransportState(channel_stats.dtls_state);
Jonas Oreland149dc722019-08-28 08:10:27 +02001705 transport_stats->selected_candidate_pair_changes =
1706 channel_stats.ice_transport_stats.selected_candidate_pair_changes;
hbos2fa7c672016-10-24 04:00:05 -07001707 for (const cricket::ConnectionInfo& info :
Jonas Oreland149dc722019-08-28 08:10:27 +02001708 channel_stats.ice_transport_stats.connection_infos) {
hbos2fa7c672016-10-24 04:00:05 -07001709 *transport_stats->bytes_sent += info.sent_total_bytes;
1710 *transport_stats->bytes_received += info.recv_total_bytes;
1711 if (info.best_connection) {
hbos2fa7c672016-10-24 04:00:05 -07001712 transport_stats->selected_candidate_pair_id =
1713 RTCIceCandidatePairStatsIDFromConnectionInfo(info);
1714 }
1715 }
1716 if (channel_stats.component != cricket::ICE_CANDIDATE_COMPONENT_RTCP &&
1717 !rtcp_transport_stats_id.empty()) {
1718 transport_stats->rtcp_transport_stats_id = rtcp_transport_stats_id;
1719 }
1720 if (!local_certificate_id.empty())
1721 transport_stats->local_certificate_id = local_certificate_id;
1722 if (!remote_certificate_id.empty())
1723 transport_stats->remote_certificate_id = remote_certificate_id;
1724 report->AddStats(std::move(transport_stats));
1725 }
1726 }
1727}
1728
1729std::map<std::string, RTCStatsCollector::CertificateStatsPair>
hbosdf6075a2016-12-19 04:58:02 -08001730RTCStatsCollector::PrepareTransportCertificateStats_n(
Steve Anton5dfde182018-02-06 10:34:40 -08001731 const std::map<std::string, cricket::TransportStats>&
1732 transport_stats_by_name) const {
hbosdf6075a2016-12-19 04:58:02 -08001733 RTC_DCHECK(network_thread_->IsCurrent());
hbos2fa7c672016-10-24 04:00:05 -07001734 std::map<std::string, CertificateStatsPair> transport_cert_stats;
Steve Anton5dfde182018-02-06 10:34:40 -08001735 for (const auto& entry : transport_stats_by_name) {
1736 const std::string& transport_name = entry.first;
1737
hbos2fa7c672016-10-24 04:00:05 -07001738 CertificateStatsPair certificate_stats_pair;
1739 rtc::scoped_refptr<rtc::RTCCertificate> local_certificate;
Steve Anton5dfde182018-02-06 10:34:40 -08001740 if (pc_->GetLocalCertificate(transport_name, &local_certificate)) {
hbos2fa7c672016-10-24 04:00:05 -07001741 certificate_stats_pair.local =
Benjamin Wright6c6c9df2018-10-25 01:16:26 -07001742 local_certificate->GetSSLCertificateChain().GetStats();
hbos2fa7c672016-10-24 04:00:05 -07001743 }
Steve Anton5dfde182018-02-06 10:34:40 -08001744
Taylor Brandstetterc3928662018-02-23 13:04:51 -08001745 std::unique_ptr<rtc::SSLCertChain> remote_cert_chain =
1746 pc_->GetRemoteSSLCertChain(transport_name);
1747 if (remote_cert_chain) {
1748 certificate_stats_pair.remote = remote_cert_chain->GetStats();
hbos2fa7c672016-10-24 04:00:05 -07001749 }
Steve Anton5dfde182018-02-06 10:34:40 -08001750
hbos2fa7c672016-10-24 04:00:05 -07001751 transport_cert_stats.insert(
Steve Anton5dfde182018-02-06 10:34:40 -08001752 std::make_pair(transport_name, std::move(certificate_stats_pair)));
hbos2fa7c672016-10-24 04:00:05 -07001753 }
1754 return transport_cert_stats;
1755}
1756
Steve Anton57858b32018-02-15 15:19:50 -08001757std::vector<RTCStatsCollector::RtpTransceiverStatsInfo>
1758RTCStatsCollector::PrepareTransceiverStatsInfos_s() const {
1759 std::vector<RtpTransceiverStatsInfo> transceiver_stats_infos;
Steve Anton56bae8d2018-02-14 16:07:42 -08001760
Steve Anton57858b32018-02-15 15:19:50 -08001761 // These are used to invoke GetStats for all the media channels together in
1762 // one worker thread hop.
1763 std::map<cricket::VoiceMediaChannel*,
1764 std::unique_ptr<cricket::VoiceMediaInfo>>
1765 voice_stats;
1766 std::map<cricket::VideoMediaChannel*,
1767 std::unique_ptr<cricket::VideoMediaInfo>>
1768 video_stats;
1769
Mirko Bonadei739baf02019-01-27 17:29:42 +01001770 for (const auto& transceiver : pc_->GetTransceiversInternal()) {
Steve Anton57858b32018-02-15 15:19:50 -08001771 cricket::MediaType media_type = transceiver->media_type();
1772
1773 // Prepare stats entry. The TrackMediaInfoMap will be filled in after the
1774 // stats have been fetched on the worker thread.
1775 transceiver_stats_infos.emplace_back();
1776 RtpTransceiverStatsInfo& stats = transceiver_stats_infos.back();
1777 stats.transceiver = transceiver->internal();
1778 stats.media_type = media_type;
1779
Amit Hilbuchdd9390c2018-11-13 16:26:05 -08001780 cricket::ChannelInterface* channel = transceiver->internal()->channel();
Steve Anton57858b32018-02-15 15:19:50 -08001781 if (!channel) {
1782 // The remaining fields require a BaseChannel.
1783 continue;
1784 }
1785
1786 stats.mid = channel->content_name();
1787 stats.transport_name = channel->transport_name();
1788
1789 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
1790 auto* voice_channel = static_cast<cricket::VoiceChannel*>(channel);
1791 RTC_DCHECK(voice_stats.find(voice_channel->media_channel()) ==
1792 voice_stats.end());
1793 voice_stats[voice_channel->media_channel()] =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001794 std::make_unique<cricket::VoiceMediaInfo>();
Steve Anton57858b32018-02-15 15:19:50 -08001795 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1796 auto* video_channel = static_cast<cricket::VideoChannel*>(channel);
1797 RTC_DCHECK(video_stats.find(video_channel->media_channel()) ==
1798 video_stats.end());
1799 video_stats[video_channel->media_channel()] =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001800 std::make_unique<cricket::VideoMediaInfo>();
Steve Anton57858b32018-02-15 15:19:50 -08001801 } else {
1802 RTC_NOTREACHED();
1803 }
Guido Urdanetaee2388f2018-02-15 16:36:19 +00001804 }
Steve Anton57858b32018-02-15 15:19:50 -08001805
1806 // Call GetStats for all media channels together on the worker thread in one
1807 // hop.
1808 worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
1809 for (const auto& entry : voice_stats) {
1810 if (!entry.first->GetStats(entry.second.get())) {
1811 RTC_LOG(LS_WARNING) << "Failed to get voice stats.";
1812 }
1813 }
1814 for (const auto& entry : video_stats) {
1815 if (!entry.first->GetStats(entry.second.get())) {
1816 RTC_LOG(LS_WARNING) << "Failed to get video stats.";
1817 }
1818 }
1819 });
1820
1821 // Create the TrackMediaInfoMap for each transceiver stats object.
1822 for (auto& stats : transceiver_stats_infos) {
1823 auto transceiver = stats.transceiver;
1824 std::unique_ptr<cricket::VoiceMediaInfo> voice_media_info;
1825 std::unique_ptr<cricket::VideoMediaInfo> video_media_info;
1826 if (transceiver->channel()) {
1827 cricket::MediaType media_type = transceiver->media_type();
1828 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
1829 auto* voice_channel =
1830 static_cast<cricket::VoiceChannel*>(transceiver->channel());
1831 RTC_DCHECK(voice_stats[voice_channel->media_channel()]);
1832 voice_media_info =
1833 std::move(voice_stats[voice_channel->media_channel()]);
1834 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1835 auto* video_channel =
1836 static_cast<cricket::VideoChannel*>(transceiver->channel());
1837 RTC_DCHECK(video_stats[video_channel->media_channel()]);
1838 video_media_info =
1839 std::move(video_stats[video_channel->media_channel()]);
1840 }
1841 }
1842 std::vector<rtc::scoped_refptr<RtpSenderInternal>> senders;
Mirko Bonadei739baf02019-01-27 17:29:42 +01001843 for (const auto& sender : transceiver->senders()) {
Steve Anton57858b32018-02-15 15:19:50 -08001844 senders.push_back(sender->internal());
1845 }
1846 std::vector<rtc::scoped_refptr<RtpReceiverInternal>> receivers;
Mirko Bonadei739baf02019-01-27 17:29:42 +01001847 for (const auto& receiver : transceiver->receivers()) {
Steve Anton57858b32018-02-15 15:19:50 -08001848 receivers.push_back(receiver->internal());
1849 }
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001850 stats.track_media_info_map = std::make_unique<TrackMediaInfoMap>(
Steve Anton57858b32018-02-15 15:19:50 -08001851 std::move(voice_media_info), std::move(video_media_info), senders,
1852 receivers);
Guido Urdanetaee2388f2018-02-15 16:36:19 +00001853 }
Steve Anton57858b32018-02-15 15:19:50 -08001854
1855 return transceiver_stats_infos;
hbos0adb8282016-11-23 02:32:06 -08001856}
1857
Steve Anton7eca0932018-03-30 15:18:41 -07001858std::set<std::string> RTCStatsCollector::PrepareTransportNames_s() const {
1859 std::set<std::string> transport_names;
1860 for (const auto& transceiver : pc_->GetTransceiversInternal()) {
1861 if (transceiver->internal()->channel()) {
1862 transport_names.insert(
1863 transceiver->internal()->channel()->transport_name());
1864 }
1865 }
1866 if (pc_->rtp_data_channel()) {
1867 transport_names.insert(pc_->rtp_data_channel()->transport_name());
1868 }
1869 if (pc_->sctp_transport_name()) {
1870 transport_names.insert(*pc_->sctp_transport_name());
1871 }
1872 return transport_names;
1873}
1874
hbos82ebe022016-11-14 01:41:09 -08001875void RTCStatsCollector::OnDataChannelCreated(DataChannel* channel) {
1876 channel->SignalOpened.connect(this, &RTCStatsCollector::OnDataChannelOpened);
1877 channel->SignalClosed.connect(this, &RTCStatsCollector::OnDataChannelClosed);
1878}
1879
1880void RTCStatsCollector::OnDataChannelOpened(DataChannel* channel) {
1881 RTC_DCHECK(signaling_thread_->IsCurrent());
Jonas Olssona4d87372019-07-05 19:08:33 +02001882 bool result = internal_record_.opened_data_channels
1883 .insert(reinterpret_cast<uintptr_t>(channel))
1884 .second;
hbos82ebe022016-11-14 01:41:09 -08001885 ++internal_record_.data_channels_opened;
1886 RTC_DCHECK(result);
1887}
1888
1889void RTCStatsCollector::OnDataChannelClosed(DataChannel* channel) {
1890 RTC_DCHECK(signaling_thread_->IsCurrent());
1891 // Only channels that have been fully opened (and have increased the
1892 // |data_channels_opened_| counter) increase the closed counter.
hbos5bf9def2017-03-20 03:14:14 -07001893 if (internal_record_.opened_data_channels.erase(
1894 reinterpret_cast<uintptr_t>(channel))) {
hbos82ebe022016-11-14 01:41:09 -08001895 ++internal_record_.data_channels_closed;
1896 }
1897}
1898
hboscc555c52016-10-18 12:48:31 -07001899const char* CandidateTypeToRTCIceCandidateTypeForTesting(
1900 const std::string& type) {
1901 return CandidateTypeToRTCIceCandidateType(type);
1902}
1903
1904const char* DataStateToRTCDataChannelStateForTesting(
1905 DataChannelInterface::DataState state) {
1906 return DataStateToRTCDataChannelState(state);
1907}
1908
hbosd565b732016-08-30 14:04:35 -07001909} // namespace webrtc