blob: c68f019ee33b37006f34e945a4ac1ad0cd6fb5b0 [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
Harald Alvestrandc24a2182022-02-23 13:44:59 +000013#include <stdint.h>
Harald Alvestrand5761e7b2021-01-29 14:45:08 +000014#include <stdio.h>
Artem Titovd15a5752021-02-10 14:31:24 +010015
Harald Alvestrand5761e7b2021-01-29 14:45:08 +000016#include <cstdint>
Johannes Kron72d69152020-02-10 14:05:55 +010017#include <map>
hbosd565b732016-08-30 14:04:35 -070018#include <memory>
Steve Anton36b29d12017-10-30 09:57:42 -070019#include <string>
Harald Alvestrandc24a2182022-02-23 13:44:59 +000020#include <type_traits>
hbosd565b732016-08-30 14:04:35 -070021#include <utility>
22#include <vector>
23
Harald Alvestrandc24a2182022-02-23 13:44:59 +000024#include "absl/strings/string_view.h"
Harald Alvestrand5761e7b2021-01-29 14:45:08 +000025#include "api/array_view.h"
Patrik Höglunde2d6a062017-10-05 14:53:33 +020026#include "api/candidate.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000027#include "api/dtls_transport_interface.h"
Steve Anton10542f22019-01-11 09:11:00 -080028#include "api/media_stream_interface.h"
Harald Alvestrand5761e7b2021-01-29 14:45:08 +000029#include "api/rtp_parameters.h"
Artem Titovd15a5752021-02-10 14:31:24 +010030#include "api/sequence_checker.h"
Harald Alvestrand5761e7b2021-01-29 14:45:08 +000031#include "api/stats/rtc_stats.h"
32#include "api/stats/rtcstats_objects.h"
33#include "api/task_queue/queued_task.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000034#include "api/units/time_delta.h"
Henrik Boström2e069262019-04-09 13:59:31 +020035#include "api/video/video_content_type.h"
Harald Alvestrand5761e7b2021-01-29 14:45:08 +000036#include "common_video/include/quality_limitation_reason.h"
Steve Anton10542f22019-01-11 09:11:00 -080037#include "media/base/media_channel.h"
Harald Alvestrand5761e7b2021-01-29 14:45:08 +000038#include "modules/audio_processing/include/audio_processing_statistics.h"
39#include "modules/rtp_rtcp/include/report_block_data.h"
40#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
41#include "p2p/base/connection_info.h"
Harald Alvestrand5761e7b2021-01-29 14:45:08 +000042#include "p2p/base/ice_transport_internal.h"
Steve Anton10542f22019-01-11 09:11:00 -080043#include "p2p/base/p2p_constants.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020044#include "p2p/base/port.h"
Harald Alvestrand5761e7b2021-01-29 14:45:08 +000045#include "pc/channel_interface.h"
46#include "pc/data_channel_utils.h"
Steve Anton10542f22019-01-11 09:11:00 -080047#include "pc/rtc_stats_traversal.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000048#include "pc/rtp_receiver_proxy.h"
49#include "pc/rtp_sender_proxy.h"
Johannes Kron72d69152020-02-10 14:05:55 +010050#include "pc/webrtc_sdp.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020051#include "rtc_base/checks.h"
Harald Alvestrand5761e7b2021-01-29 14:45:08 +000052#include "rtc_base/ip_address.h"
53#include "rtc_base/location.h"
54#include "rtc_base/logging.h"
55#include "rtc_base/network_constants.h"
56#include "rtc_base/ref_counted_object.h"
57#include "rtc_base/rtc_certificate.h"
58#include "rtc_base/socket_address.h"
59#include "rtc_base/ssl_stream_adapter.h"
60#include "rtc_base/string_encode.h"
Jonas Olsson43568dd2018-06-11 16:25:54 +020061#include "rtc_base/strings/string_builder.h"
Steve Anton10542f22019-01-11 09:11:00 -080062#include "rtc_base/time_utils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020063#include "rtc_base/trace_event.h"
hbosd565b732016-08-30 14:04:35 -070064
65namespace webrtc {
66
hboscc555c52016-10-18 12:48:31 -070067namespace {
68
Henrik Boström646fda02019-05-22 15:49:42 +020069// TODO(https://crbug.com/webrtc/10656): Consider making IDs less predictable.
hbos2fa7c672016-10-24 04:00:05 -070070std::string RTCCertificateIDFromFingerprint(const std::string& fingerprint) {
71 return "RTCCertificate_" + fingerprint;
72}
73
Steve Anton57858b32018-02-15 15:19:50 -080074std::string RTCCodecStatsIDFromMidDirectionAndPayload(const std::string& mid,
75 bool inbound,
76 uint32_t payload_type) {
Jonas Olsson43568dd2018-06-11 16:25:54 +020077 char buf[1024];
78 rtc::SimpleStringBuilder sb(buf);
79 sb << "RTCCodec_" << mid << (inbound ? "_Inbound_" : "_Outbound_")
80 << payload_type;
81 return sb.str();
hbos0adb8282016-11-23 02:32:06 -080082}
83
hbos2fa7c672016-10-24 04:00:05 -070084std::string RTCIceCandidatePairStatsIDFromConnectionInfo(
85 const cricket::ConnectionInfo& info) {
Jonas Olsson43568dd2018-06-11 16:25:54 +020086 char buf[4096];
87 rtc::SimpleStringBuilder sb(buf);
88 sb << "RTCIceCandidatePair_" << info.local_candidate.id() << "_"
89 << info.remote_candidate.id();
90 return sb.str();
hbos2fa7c672016-10-24 04:00:05 -070091}
92
Harald Alvestranda3dab842018-01-14 09:18:58 +010093const char kSender[] = "sender";
94const char kReceiver[] = "receiver";
95
96std::string RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
97 const char* direction,
Harald Alvestrandc72af932018-01-11 17:18:19 +010098 int attachment_id) {
Jonas Olsson43568dd2018-06-11 16:25:54 +020099 char buf[1024];
100 rtc::SimpleStringBuilder sb(buf);
101 sb << "RTCMediaStreamTrack_" << direction << "_" << attachment_id;
102 return sb.str();
hbos09bc1282016-11-08 06:29:22 -0800103}
104
hbos2fa7c672016-10-24 04:00:05 -0700105std::string RTCTransportStatsIDFromTransportChannel(
Jonas Olssona4d87372019-07-05 19:08:33 +0200106 const std::string& transport_name,
107 int channel_component) {
Jonas Olsson43568dd2018-06-11 16:25:54 +0200108 char buf[1024];
109 rtc::SimpleStringBuilder sb(buf);
110 sb << "RTCTransport_" << transport_name << "_" << channel_component;
111 return sb.str();
hbos2fa7c672016-10-24 04:00:05 -0700112}
113
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +0100114std::string RTCInboundRTPStreamStatsIDFromSSRC(cricket::MediaType media_type,
115 uint32_t ssrc) {
Jonas Olsson43568dd2018-06-11 16:25:54 +0200116 char buf[1024];
117 rtc::SimpleStringBuilder sb(buf);
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +0100118 sb << "RTCInboundRTP"
119 << (media_type == cricket::MEDIA_TYPE_AUDIO ? "Audio" : "Video")
120 << "Stream_" << ssrc;
Jonas Olsson43568dd2018-06-11 16:25:54 +0200121 return sb.str();
hboseeafe942016-11-01 03:00:17 -0700122}
123
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +0100124std::string RTCOutboundRTPStreamStatsIDFromSSRC(cricket::MediaType media_type,
125 uint32_t ssrc) {
Jonas Olsson43568dd2018-06-11 16:25:54 +0200126 char buf[1024];
127 rtc::SimpleStringBuilder sb(buf);
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +0100128 sb << "RTCOutboundRTP"
129 << (media_type == cricket::MEDIA_TYPE_AUDIO ? "Audio" : "Video")
130 << "Stream_" << ssrc;
Jonas Olsson43568dd2018-06-11 16:25:54 +0200131 return sb.str();
hbos6ded1902016-11-01 01:50:46 -0700132}
133
Henrik Boström8605fbf2019-06-24 16:44:51 +0200134std::string RTCRemoteInboundRtpStreamStatsIdFromSourceSsrc(
Henrik Boström883eefc2019-05-27 13:40:25 +0200135 cricket::MediaType media_type,
Henrik Boström883eefc2019-05-27 13:40:25 +0200136 uint32_t source_ssrc) {
137 char buf[1024];
138 rtc::SimpleStringBuilder sb(buf);
139 sb << "RTCRemoteInboundRtp"
140 << (media_type == cricket::MEDIA_TYPE_AUDIO ? "Audio" : "Video")
Henrik Boström8605fbf2019-06-24 16:44:51 +0200141 << "Stream_" << source_ssrc;
Henrik Boström883eefc2019-05-27 13:40:25 +0200142 return sb.str();
143}
144
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +0100145std::string RTCRemoteOutboundRTPStreamStatsIDFromSSRC(
146 cricket::MediaType media_type,
147 uint32_t source_ssrc) {
148 char buf[1024];
149 rtc::SimpleStringBuilder sb(buf);
150 sb << "RTCRemoteOutboundRTP"
151 << (media_type == cricket::MEDIA_TYPE_AUDIO ? "Audio" : "Video")
152 << "Stream_" << source_ssrc;
153 return sb.str();
154}
155
Henrik Boström646fda02019-05-22 15:49:42 +0200156std::string RTCMediaSourceStatsIDFromKindAndAttachment(
157 cricket::MediaType media_type,
158 int attachment_id) {
159 char buf[1024];
160 rtc::SimpleStringBuilder sb(buf);
161 sb << "RTC" << (media_type == cricket::MEDIA_TYPE_AUDIO ? "Audio" : "Video")
162 << "Source_" << attachment_id;
163 return sb.str();
164}
165
hbosab9f6e42016-10-07 02:18:47 -0700166const char* CandidateTypeToRTCIceCandidateType(const std::string& type) {
167 if (type == cricket::LOCAL_PORT_TYPE)
168 return RTCIceCandidateType::kHost;
169 if (type == cricket::STUN_PORT_TYPE)
170 return RTCIceCandidateType::kSrflx;
171 if (type == cricket::PRFLX_PORT_TYPE)
172 return RTCIceCandidateType::kPrflx;
173 if (type == cricket::RELAY_PORT_TYPE)
174 return RTCIceCandidateType::kRelay;
Artem Titovd3251962021-11-15 16:57:07 +0100175 RTC_DCHECK_NOTREACHED();
hbosab9f6e42016-10-07 02:18:47 -0700176 return nullptr;
177}
178
hboscc555c52016-10-18 12:48:31 -0700179const char* DataStateToRTCDataChannelState(
180 DataChannelInterface::DataState state) {
181 switch (state) {
182 case DataChannelInterface::kConnecting:
183 return RTCDataChannelState::kConnecting;
184 case DataChannelInterface::kOpen:
185 return RTCDataChannelState::kOpen;
186 case DataChannelInterface::kClosing:
187 return RTCDataChannelState::kClosing;
188 case DataChannelInterface::kClosed:
189 return RTCDataChannelState::kClosed;
190 default:
Artem Titovd3251962021-11-15 16:57:07 +0100191 RTC_DCHECK_NOTREACHED();
hboscc555c52016-10-18 12:48:31 -0700192 return nullptr;
193 }
194}
195
hbos06495bc2017-01-02 08:08:18 -0800196const char* IceCandidatePairStateToRTCStatsIceCandidatePairState(
197 cricket::IceCandidatePairState state) {
198 switch (state) {
199 case cricket::IceCandidatePairState::WAITING:
200 return RTCStatsIceCandidatePairState::kWaiting;
201 case cricket::IceCandidatePairState::IN_PROGRESS:
202 return RTCStatsIceCandidatePairState::kInProgress;
203 case cricket::IceCandidatePairState::SUCCEEDED:
204 return RTCStatsIceCandidatePairState::kSucceeded;
205 case cricket::IceCandidatePairState::FAILED:
206 return RTCStatsIceCandidatePairState::kFailed;
207 default:
Artem Titovd3251962021-11-15 16:57:07 +0100208 RTC_DCHECK_NOTREACHED();
hbos06495bc2017-01-02 08:08:18 -0800209 return nullptr;
210 }
211}
212
Philipp Hanckecc1b9b02022-05-04 18:58:26 +0200213const char* IceRoleToRTCIceRole(cricket::IceRole role) {
214 switch (role) {
215 case cricket::IceRole::ICEROLE_UNKNOWN:
216 return RTCIceRole::kUnknown;
217 case cricket::IceRole::ICEROLE_CONTROLLED:
218 return RTCIceRole::kControlled;
219 case cricket::IceRole::ICEROLE_CONTROLLING:
220 return RTCIceRole::kControlling;
221 default:
222 RTC_DCHECK_NOTREACHED();
223 return nullptr;
224 }
225}
226
hbos7064d592017-01-16 07:38:02 -0800227const char* DtlsTransportStateToRTCDtlsTransportState(
Mirko Bonadei9f6808b2021-05-21 20:46:09 +0200228 DtlsTransportState state) {
hbos7064d592017-01-16 07:38:02 -0800229 switch (state) {
Mirko Bonadei9f6808b2021-05-21 20:46:09 +0200230 case DtlsTransportState::kNew:
hbos7064d592017-01-16 07:38:02 -0800231 return RTCDtlsTransportState::kNew;
Mirko Bonadei9f6808b2021-05-21 20:46:09 +0200232 case DtlsTransportState::kConnecting:
hbos7064d592017-01-16 07:38:02 -0800233 return RTCDtlsTransportState::kConnecting;
Mirko Bonadei9f6808b2021-05-21 20:46:09 +0200234 case DtlsTransportState::kConnected:
hbos7064d592017-01-16 07:38:02 -0800235 return RTCDtlsTransportState::kConnected;
Mirko Bonadei9f6808b2021-05-21 20:46:09 +0200236 case DtlsTransportState::kClosed:
hbos7064d592017-01-16 07:38:02 -0800237 return RTCDtlsTransportState::kClosed;
Mirko Bonadei9f6808b2021-05-21 20:46:09 +0200238 case DtlsTransportState::kFailed:
hbos7064d592017-01-16 07:38:02 -0800239 return RTCDtlsTransportState::kFailed;
240 default:
Mirko Bonadei9f6808b2021-05-21 20:46:09 +0200241 RTC_CHECK_NOTREACHED();
hbos7064d592017-01-16 07:38:02 -0800242 return nullptr;
243 }
244}
245
Jonas Oreland0d13bbd2022-03-02 11:17:36 +0100246const char* NetworkTypeToStatsType(rtc::AdapterType type) {
Gary Liu37e489c2017-11-21 10:49:36 -0800247 switch (type) {
248 case rtc::ADAPTER_TYPE_CELLULAR:
Jonas Oreland08d18062020-04-02 07:19:12 +0200249 case rtc::ADAPTER_TYPE_CELLULAR_2G:
250 case rtc::ADAPTER_TYPE_CELLULAR_3G:
251 case rtc::ADAPTER_TYPE_CELLULAR_4G:
252 case rtc::ADAPTER_TYPE_CELLULAR_5G:
Gary Liu37e489c2017-11-21 10:49:36 -0800253 return RTCNetworkType::kCellular;
254 case rtc::ADAPTER_TYPE_ETHERNET:
255 return RTCNetworkType::kEthernet;
256 case rtc::ADAPTER_TYPE_WIFI:
257 return RTCNetworkType::kWifi;
258 case rtc::ADAPTER_TYPE_VPN:
259 return RTCNetworkType::kVpn;
260 case rtc::ADAPTER_TYPE_UNKNOWN:
261 case rtc::ADAPTER_TYPE_LOOPBACK:
Qingsi Wang9f1de692018-06-28 15:38:09 -0700262 case rtc::ADAPTER_TYPE_ANY:
Gary Liu37e489c2017-11-21 10:49:36 -0800263 return RTCNetworkType::kUnknown;
264 }
Artem Titovd3251962021-11-15 16:57:07 +0100265 RTC_DCHECK_NOTREACHED();
Gary Liu37e489c2017-11-21 10:49:36 -0800266 return nullptr;
267}
268
Jonas Oreland0d13bbd2022-03-02 11:17:36 +0100269absl::string_view NetworkTypeToStatsNetworkAdapterType(rtc::AdapterType type) {
270 switch (type) {
271 case rtc::ADAPTER_TYPE_CELLULAR:
272 return RTCNetworkAdapterType::kCellular;
273 case rtc::ADAPTER_TYPE_CELLULAR_2G:
274 return RTCNetworkAdapterType::kCellular2g;
275 case rtc::ADAPTER_TYPE_CELLULAR_3G:
276 return RTCNetworkAdapterType::kCellular3g;
277 case rtc::ADAPTER_TYPE_CELLULAR_4G:
278 return RTCNetworkAdapterType::kCellular4g;
279 case rtc::ADAPTER_TYPE_CELLULAR_5G:
280 return RTCNetworkAdapterType::kCellular5g;
281 case rtc::ADAPTER_TYPE_ETHERNET:
282 return RTCNetworkAdapterType::kEthernet;
283 case rtc::ADAPTER_TYPE_WIFI:
284 return RTCNetworkAdapterType::kWifi;
285 case rtc::ADAPTER_TYPE_UNKNOWN:
286 return RTCNetworkAdapterType::kUnknown;
287 case rtc::ADAPTER_TYPE_LOOPBACK:
288 return RTCNetworkAdapterType::kLoopback;
289 case rtc::ADAPTER_TYPE_ANY:
290 return RTCNetworkAdapterType::kAny;
291 case rtc::ADAPTER_TYPE_VPN:
292 /* should not be handled here. Vpn is modelled as a bool */
293 break;
294 }
295 RTC_DCHECK_NOTREACHED();
Mirko Bonadei23e46542022-04-07 17:27:15 +0200296 return {};
Jonas Oreland0d13bbd2022-03-02 11:17:36 +0100297}
298
Henrik Boströmce33b6a2019-05-28 17:42:38 +0200299const char* QualityLimitationReasonToRTCQualityLimitationReason(
300 QualityLimitationReason reason) {
301 switch (reason) {
302 case QualityLimitationReason::kNone:
303 return RTCQualityLimitationReason::kNone;
304 case QualityLimitationReason::kCpu:
305 return RTCQualityLimitationReason::kCpu;
306 case QualityLimitationReason::kBandwidth:
307 return RTCQualityLimitationReason::kBandwidth;
308 case QualityLimitationReason::kOther:
309 return RTCQualityLimitationReason::kOther;
310 }
Karl Wibergc95b9392020-11-08 00:49:37 +0100311 RTC_CHECK_NOTREACHED();
Henrik Boströmce33b6a2019-05-28 17:42:38 +0200312}
313
Byoungchan Lee7d235352021-05-28 21:32:04 +0900314std::map<std::string, double>
315QualityLimitationDurationToRTCQualityLimitationDuration(
316 std::map<webrtc::QualityLimitationReason, int64_t> durations_ms) {
317 std::map<std::string, double> result;
Philipp Hancke3fd9cbc2022-01-10 17:41:43 +0100318 // The internal duration is defined in milliseconds while the spec defines
319 // the value in seconds:
320 // https://w3c.github.io/webrtc-stats/#dom-rtcoutboundrtpstreamstats-qualitylimitationdurations
Byoungchan Lee7d235352021-05-28 21:32:04 +0900321 for (const auto& elem : durations_ms) {
322 result[QualityLimitationReasonToRTCQualityLimitationReason(elem.first)] =
Philipp Hancke3fd9cbc2022-01-10 17:41:43 +0100323 elem.second / static_cast<double>(rtc::kNumMillisecsPerSec);
Byoungchan Lee7d235352021-05-28 21:32:04 +0900324 }
325 return result;
326}
327
hbos9e302742017-01-20 02:47:10 -0800328double DoubleAudioLevelFromIntAudioLevel(int audio_level) {
329 RTC_DCHECK_GE(audio_level, 0);
330 RTC_DCHECK_LE(audio_level, 32767);
331 return audio_level / 32767.0;
332}
333
hbos0adb8282016-11-23 02:32:06 -0800334std::unique_ptr<RTCCodecStats> CodecStatsFromRtpCodecParameters(
Steve Anton57858b32018-02-15 15:19:50 -0800335 uint64_t timestamp_us,
336 const std::string& mid,
Philipp Hancke95157a02020-11-16 20:08:27 +0100337 const std::string& transport_id,
Steve Anton57858b32018-02-15 15:19:50 -0800338 bool inbound,
hbos0adb8282016-11-23 02:32:06 -0800339 const RtpCodecParameters& codec_params) {
340 RTC_DCHECK_GE(codec_params.payload_type, 0);
341 RTC_DCHECK_LE(codec_params.payload_type, 127);
deadbeefe702b302017-02-04 12:09:01 -0800342 RTC_DCHECK(codec_params.clock_rate);
hbos0adb8282016-11-23 02:32:06 -0800343 uint32_t payload_type = static_cast<uint32_t>(codec_params.payload_type);
344 std::unique_ptr<RTCCodecStats> codec_stats(new RTCCodecStats(
Steve Anton57858b32018-02-15 15:19:50 -0800345 RTCCodecStatsIDFromMidDirectionAndPayload(mid, inbound, payload_type),
hbos0adb8282016-11-23 02:32:06 -0800346 timestamp_us));
347 codec_stats->payload_type = payload_type;
hbos13f54b22017-02-28 06:56:04 -0800348 codec_stats->mime_type = codec_params.mime_type();
deadbeefe702b302017-02-04 12:09:01 -0800349 if (codec_params.clock_rate) {
350 codec_stats->clock_rate = static_cast<uint32_t>(*codec_params.clock_rate);
351 }
Johannes Kron72d69152020-02-10 14:05:55 +0100352 if (codec_params.num_channels) {
353 codec_stats->channels = *codec_params.num_channels;
354 }
355
356 rtc::StringBuilder fmtp;
357 if (WriteFmtpParameters(codec_params.parameters, &fmtp)) {
358 codec_stats->sdp_fmtp_line = fmtp.Release();
359 }
Philipp Hancke95157a02020-11-16 20:08:27 +0100360 codec_stats->transport_id = transport_id;
hbos0adb8282016-11-23 02:32:06 -0800361 return codec_stats;
362}
363
hbos09bc1282016-11-08 06:29:22 -0800364void SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
365 const MediaStreamTrackInterface& track,
366 RTCMediaStreamTrackStats* track_stats) {
367 track_stats->track_identifier = track.id();
368 track_stats->ended = (track.state() == MediaStreamTrackInterface::kEnded);
369}
370
hbos820f5782016-11-22 03:16:50 -0800371// Provides the media independent counters (both audio and video).
hboseeafe942016-11-01 03:00:17 -0700372void SetInboundRTPStreamStatsFromMediaReceiverInfo(
373 const cricket::MediaReceiverInfo& media_receiver_info,
374 RTCInboundRTPStreamStats* inbound_stats) {
375 RTC_DCHECK(inbound_stats);
hbos3443bb72017-02-07 06:28:11 -0800376 inbound_stats->ssrc = media_receiver_info.ssrc();
hboseeafe942016-11-01 03:00:17 -0700377 inbound_stats->packets_received =
378 static_cast<uint32_t>(media_receiver_info.packets_rcvd);
379 inbound_stats->bytes_received =
Niels Möllerac0a4cb2019-10-09 15:01:33 +0200380 static_cast<uint64_t>(media_receiver_info.payload_bytes_rcvd);
381 inbound_stats->header_bytes_received =
382 static_cast<uint64_t>(media_receiver_info.header_and_padding_bytes_rcvd);
hbos02cd4d62016-12-09 04:19:44 -0800383 inbound_stats->packets_lost =
Harald Alvestrand719487e2017-12-13 12:26:04 +0100384 static_cast<int32_t>(media_receiver_info.packets_lost);
Byoungchan Lee899b29e2021-06-29 22:09:18 +0900385 inbound_stats->jitter_buffer_delay =
386 media_receiver_info.jitter_buffer_delay_seconds;
387 inbound_stats->jitter_buffer_emitted_count =
388 media_receiver_info.jitter_buffer_emitted_count;
Jakob Ivarssone54914a2021-07-01 11:16:05 +0200389 if (media_receiver_info.nacks_sent) {
390 inbound_stats->nack_count = *media_receiver_info.nacks_sent;
391 }
hboseeafe942016-11-01 03:00:17 -0700392}
393
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +0100394std::unique_ptr<RTCInboundRTPStreamStats> CreateInboundAudioStreamStats(
hboseeafe942016-11-01 03:00:17 -0700395 const cricket::VoiceReceiverInfo& voice_receiver_info,
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +0100396 const std::string& mid,
397 int64_t timestamp_us) {
398 auto inbound_audio = std::make_unique<RTCInboundRTPStreamStats>(
399 /*id=*/RTCInboundRTPStreamStatsIDFromSSRC(cricket::MEDIA_TYPE_AUDIO,
400 voice_receiver_info.ssrc()),
401 timestamp_us);
Jonas Olssona4d87372019-07-05 19:08:33 +0200402 SetInboundRTPStreamStatsFromMediaReceiverInfo(voice_receiver_info,
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +0100403 inbound_audio.get());
hbos820f5782016-11-22 03:16:50 -0800404 inbound_audio->media_type = "audio";
Philipp Hancke3bc01662018-08-28 14:55:03 +0200405 inbound_audio->kind = "audio";
hbos585a9b12017-02-07 04:59:16 -0800406 if (voice_receiver_info.codec_payload_type) {
Steve Anton57858b32018-02-15 15:19:50 -0800407 inbound_audio->codec_id = RTCCodecStatsIDFromMidDirectionAndPayload(
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +0100408 mid, /*inbound=*/true, *voice_receiver_info.codec_payload_type);
hbos585a9b12017-02-07 04:59:16 -0800409 }
Jonas Olssona4d87372019-07-05 19:08:33 +0200410 inbound_audio->jitter = static_cast<double>(voice_receiver_info.jitter_ms) /
411 rtc::kNumMillisecsPerSec;
Eldar Rello4e5bc9f2020-07-06 14:18:07 +0300412 inbound_audio->total_samples_received =
413 voice_receiver_info.total_samples_received;
414 inbound_audio->concealed_samples = voice_receiver_info.concealed_samples;
415 inbound_audio->silent_concealed_samples =
416 voice_receiver_info.silent_concealed_samples;
417 inbound_audio->concealment_events = voice_receiver_info.concealment_events;
418 inbound_audio->inserted_samples_for_deceleration =
419 voice_receiver_info.inserted_samples_for_deceleration;
420 inbound_audio->removed_samples_for_acceleration =
421 voice_receiver_info.removed_samples_for_acceleration;
Philipp Hanckeaa83cc72020-10-27 09:50:36 +0100422 if (voice_receiver_info.audio_level >= 0) {
423 inbound_audio->audio_level =
424 DoubleAudioLevelFromIntAudioLevel(voice_receiver_info.audio_level);
425 }
Eldar Rello4e5bc9f2020-07-06 14:18:07 +0300426 inbound_audio->total_audio_energy = voice_receiver_info.total_output_energy;
427 inbound_audio->total_samples_duration =
428 voice_receiver_info.total_output_duration;
Artem Titov880fa812021-07-30 22:30:23 +0200429 // `fir_count`, `pli_count` and `sli_count` are only valid for video and are
hbos820f5782016-11-22 03:16:50 -0800430 // purposefully left undefined for audio.
Henrik Boström01738c62019-04-15 17:32:00 +0200431 if (voice_receiver_info.last_packet_received_timestamp_ms) {
Alessio Bazzicac366d512021-03-22 15:36:53 +0100432 inbound_audio->last_packet_received_timestamp = static_cast<double>(
433 *voice_receiver_info.last_packet_received_timestamp_ms);
Henrik Boström01738c62019-04-15 17:32:00 +0200434 }
Åsa Perssonfcf79cc2019-10-22 15:23:44 +0200435 if (voice_receiver_info.estimated_playout_ntp_timestamp_ms) {
Alessio Bazzica5cf8c2c2021-03-24 08:51:26 +0100436 // TODO(bugs.webrtc.org/10529): Fix time origin.
Åsa Perssonfcf79cc2019-10-22 15:23:44 +0200437 inbound_audio->estimated_playout_timestamp = static_cast<double>(
438 *voice_receiver_info.estimated_playout_ntp_timestamp_ms);
439 }
Ivo Creusen8d8ffdb2019-04-30 09:45:21 +0200440 inbound_audio->fec_packets_received =
441 voice_receiver_info.fec_packets_received;
442 inbound_audio->fec_packets_discarded =
443 voice_receiver_info.fec_packets_discarded;
Minyue Li28a2c632021-07-07 15:53:38 +0200444 inbound_audio->packets_discarded = voice_receiver_info.packets_discarded;
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +0100445 return inbound_audio;
446}
447
448std::unique_ptr<RTCRemoteOutboundRtpStreamStats>
449CreateRemoteOutboundAudioStreamStats(
450 const cricket::VoiceReceiverInfo& voice_receiver_info,
451 const std::string& mid,
452 const std::string& inbound_audio_id,
453 const std::string& transport_id) {
454 if (!voice_receiver_info.last_sender_report_timestamp_ms.has_value()) {
455 // Cannot create `RTCRemoteOutboundRtpStreamStats` when the RTCP SR arrival
456 // timestamp is not available - i.e., until the first sender report is
457 // received.
458 return nullptr;
459 }
460 RTC_DCHECK_GT(voice_receiver_info.sender_reports_reports_count, 0);
461
462 // Create.
463 auto stats = std::make_unique<RTCRemoteOutboundRtpStreamStats>(
464 /*id=*/RTCRemoteOutboundRTPStreamStatsIDFromSSRC(
465 cricket::MEDIA_TYPE_AUDIO, voice_receiver_info.ssrc()),
466 /*timestamp_us=*/rtc::kNumMicrosecsPerMillisec *
467 voice_receiver_info.last_sender_report_timestamp_ms.value());
468
469 // Populate.
470 // - RTCRtpStreamStats.
471 stats->ssrc = voice_receiver_info.ssrc();
472 stats->kind = "audio";
473 stats->transport_id = transport_id;
474 stats->codec_id = RTCCodecStatsIDFromMidDirectionAndPayload(
475 mid,
476 /*inbound=*/true, // Remote-outbound same as local-inbound.
477 *voice_receiver_info.codec_payload_type);
478 // - RTCSentRtpStreamStats.
479 stats->packets_sent = voice_receiver_info.sender_reports_packets_sent;
480 stats->bytes_sent = voice_receiver_info.sender_reports_bytes_sent;
481 // - RTCRemoteOutboundRtpStreamStats.
482 stats->local_id = inbound_audio_id;
483 RTC_DCHECK(
484 voice_receiver_info.last_sender_report_remote_timestamp_ms.has_value());
485 stats->remote_timestamp = static_cast<double>(
486 voice_receiver_info.last_sender_report_remote_timestamp_ms.value());
487 stats->reports_sent = voice_receiver_info.sender_reports_reports_count;
Ivo Creusen2562cf02021-09-03 14:51:22 +0000488 if (voice_receiver_info.round_trip_time) {
489 stats->round_trip_time =
490 voice_receiver_info.round_trip_time->seconds<double>();
491 }
492 stats->round_trip_time_measurements =
493 voice_receiver_info.round_trip_time_measurements;
494 stats->total_round_trip_time =
495 voice_receiver_info.total_round_trip_time.seconds<double>();
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +0100496
497 return stats;
hboseeafe942016-11-01 03:00:17 -0700498}
499
500void SetInboundRTPStreamStatsFromVideoReceiverInfo(
Steve Anton57858b32018-02-15 15:19:50 -0800501 const std::string& mid,
hboseeafe942016-11-01 03:00:17 -0700502 const cricket::VideoReceiverInfo& video_receiver_info,
hbos820f5782016-11-22 03:16:50 -0800503 RTCInboundRTPStreamStats* inbound_video) {
Jonas Olssona4d87372019-07-05 19:08:33 +0200504 SetInboundRTPStreamStatsFromMediaReceiverInfo(video_receiver_info,
505 inbound_video);
hbos820f5782016-11-22 03:16:50 -0800506 inbound_video->media_type = "video";
Philipp Hancke3bc01662018-08-28 14:55:03 +0200507 inbound_video->kind = "video";
hbos585a9b12017-02-07 04:59:16 -0800508 if (video_receiver_info.codec_payload_type) {
Steve Anton57858b32018-02-15 15:19:50 -0800509 inbound_video->codec_id = RTCCodecStatsIDFromMidDirectionAndPayload(
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +0100510 mid, /*inbound=*/true, *video_receiver_info.codec_payload_type);
hbos585a9b12017-02-07 04:59:16 -0800511 }
Di Wu (RP Room Eng)8af6b492021-02-19 17:34:22 -0800512 inbound_video->jitter = static_cast<double>(video_receiver_info.jitter_ms) /
513 rtc::kNumMillisecsPerSec;
hbos820f5782016-11-22 03:16:50 -0800514 inbound_video->fir_count =
515 static_cast<uint32_t>(video_receiver_info.firs_sent);
516 inbound_video->pli_count =
517 static_cast<uint32_t>(video_receiver_info.plis_sent);
Eldar Rello4e5bc9f2020-07-06 14:18:07 +0300518 inbound_video->frames_received = video_receiver_info.frames_received;
hbos6769c492017-01-02 08:35:13 -0800519 inbound_video->frames_decoded = video_receiver_info.frames_decoded;
Eldar Rello4e5bc9f2020-07-06 14:18:07 +0300520 inbound_video->frames_dropped = video_receiver_info.frames_dropped;
Rasmus Brandt2efae772019-06-27 14:29:34 +0200521 inbound_video->key_frames_decoded = video_receiver_info.key_frames_decoded;
Eldar Rello4e5bc9f2020-07-06 14:18:07 +0300522 if (video_receiver_info.frame_width > 0) {
523 inbound_video->frame_width =
524 static_cast<uint32_t>(video_receiver_info.frame_width);
525 }
526 if (video_receiver_info.frame_height > 0) {
527 inbound_video->frame_height =
528 static_cast<uint32_t>(video_receiver_info.frame_height);
529 }
530 if (video_receiver_info.framerate_rcvd > 0) {
531 inbound_video->frames_per_second = video_receiver_info.framerate_rcvd;
532 }
hbosa51d4f32017-02-16 05:34:48 -0800533 if (video_receiver_info.qp_sum)
534 inbound_video->qp_sum = *video_receiver_info.qp_sum;
Johannes Kronbfd343b2019-07-01 10:07:50 +0200535 inbound_video->total_decode_time =
536 static_cast<double>(video_receiver_info.total_decode_time_ms) /
537 rtc::kNumMillisecsPerSec;
Philipp Hanckea16a6a62022-04-25 12:21:30 +0200538 inbound_video->total_processing_delay =
539 static_cast<double>(video_receiver_info.total_processing_delay.ms()) /
540 rtc::kNumMillisecsPerSec;
Johannes Kron00376e12019-11-25 10:25:42 +0100541 inbound_video->total_inter_frame_delay =
542 video_receiver_info.total_inter_frame_delay;
543 inbound_video->total_squared_inter_frame_delay =
544 video_receiver_info.total_squared_inter_frame_delay;
Henrik Boström01738c62019-04-15 17:32:00 +0200545 if (video_receiver_info.last_packet_received_timestamp_ms) {
Alessio Bazzica5cf8c2c2021-03-24 08:51:26 +0100546 inbound_video->last_packet_received_timestamp = static_cast<double>(
547 *video_receiver_info.last_packet_received_timestamp_ms);
Henrik Boström01738c62019-04-15 17:32:00 +0200548 }
Åsa Perssonfcf79cc2019-10-22 15:23:44 +0200549 if (video_receiver_info.estimated_playout_ntp_timestamp_ms) {
Alessio Bazzica5cf8c2c2021-03-24 08:51:26 +0100550 // TODO(bugs.webrtc.org/10529): Fix time origin if needed.
Åsa Perssonfcf79cc2019-10-22 15:23:44 +0200551 inbound_video->estimated_playout_timestamp = static_cast<double>(
552 *video_receiver_info.estimated_playout_ntp_timestamp_ms);
553 }
Artem Titov880fa812021-07-30 22:30:23 +0200554 // TODO(bugs.webrtc.org/10529): When info's `content_info` is optional
Alessio Bazzica5cf8c2c2021-03-24 08:51:26 +0100555 // support the "unspecified" value.
Henrik Boström2e069262019-04-09 13:59:31 +0200556 if (video_receiver_info.content_type == VideoContentType::SCREENSHARE)
557 inbound_video->content_type = RTCContentType::kScreenshare;
Henrik Boström6b430862019-08-16 13:09:51 +0200558 if (!video_receiver_info.decoder_implementation_name.empty()) {
559 inbound_video->decoder_implementation =
560 video_receiver_info.decoder_implementation_name;
561 }
hboseeafe942016-11-01 03:00:17 -0700562}
563
hbos820f5782016-11-22 03:16:50 -0800564// Provides the media independent counters (both audio and video).
hbos6ded1902016-11-01 01:50:46 -0700565void SetOutboundRTPStreamStatsFromMediaSenderInfo(
566 const cricket::MediaSenderInfo& media_sender_info,
567 RTCOutboundRTPStreamStats* outbound_stats) {
568 RTC_DCHECK(outbound_stats);
hbos3443bb72017-02-07 06:28:11 -0800569 outbound_stats->ssrc = media_sender_info.ssrc();
hbos6ded1902016-11-01 01:50:46 -0700570 outbound_stats->packets_sent =
571 static_cast<uint32_t>(media_sender_info.packets_sent);
Henrik Boströmcf96e0f2019-04-17 13:51:53 +0200572 outbound_stats->retransmitted_packets_sent =
573 media_sender_info.retransmitted_packets_sent;
hbos6ded1902016-11-01 01:50:46 -0700574 outbound_stats->bytes_sent =
Niels Möllerac0a4cb2019-10-09 15:01:33 +0200575 static_cast<uint64_t>(media_sender_info.payload_bytes_sent);
576 outbound_stats->header_bytes_sent =
577 static_cast<uint64_t>(media_sender_info.header_and_padding_bytes_sent);
Henrik Boströmcf96e0f2019-04-17 13:51:53 +0200578 outbound_stats->retransmitted_bytes_sent =
579 media_sender_info.retransmitted_bytes_sent;
Jakob Ivarssone91c9922021-07-06 09:55:43 +0200580 outbound_stats->nack_count = media_sender_info.nacks_rcvd;
hbos6ded1902016-11-01 01:50:46 -0700581}
582
583void SetOutboundRTPStreamStatsFromVoiceSenderInfo(
Steve Anton57858b32018-02-15 15:19:50 -0800584 const std::string& mid,
hbos6ded1902016-11-01 01:50:46 -0700585 const cricket::VoiceSenderInfo& voice_sender_info,
586 RTCOutboundRTPStreamStats* outbound_audio) {
Jonas Olssona4d87372019-07-05 19:08:33 +0200587 SetOutboundRTPStreamStatsFromMediaSenderInfo(voice_sender_info,
588 outbound_audio);
hbos6ded1902016-11-01 01:50:46 -0700589 outbound_audio->media_type = "audio";
Philipp Hancke3bc01662018-08-28 14:55:03 +0200590 outbound_audio->kind = "audio";
Jakob Ivarssonbf087452021-11-11 13:43:49 +0100591 if (voice_sender_info.target_bitrate > 0) {
592 outbound_audio->target_bitrate = voice_sender_info.target_bitrate;
593 }
hbos585a9b12017-02-07 04:59:16 -0800594 if (voice_sender_info.codec_payload_type) {
Steve Anton57858b32018-02-15 15:19:50 -0800595 outbound_audio->codec_id = RTCCodecStatsIDFromMidDirectionAndPayload(
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +0100596 mid, /*inbound=*/false, *voice_sender_info.codec_payload_type);
hbos585a9b12017-02-07 04:59:16 -0800597 }
Artem Titov880fa812021-07-30 22:30:23 +0200598 // `fir_count`, `pli_count` and `sli_count` are only valid for video and are
hbos6ded1902016-11-01 01:50:46 -0700599 // purposefully left undefined for audio.
600}
601
602void SetOutboundRTPStreamStatsFromVideoSenderInfo(
Steve Anton57858b32018-02-15 15:19:50 -0800603 const std::string& mid,
hbos6ded1902016-11-01 01:50:46 -0700604 const cricket::VideoSenderInfo& video_sender_info,
605 RTCOutboundRTPStreamStats* outbound_video) {
Jonas Olssona4d87372019-07-05 19:08:33 +0200606 SetOutboundRTPStreamStatsFromMediaSenderInfo(video_sender_info,
607 outbound_video);
hbos6ded1902016-11-01 01:50:46 -0700608 outbound_video->media_type = "video";
Philipp Hancke3bc01662018-08-28 14:55:03 +0200609 outbound_video->kind = "video";
hbos585a9b12017-02-07 04:59:16 -0800610 if (video_sender_info.codec_payload_type) {
Steve Anton57858b32018-02-15 15:19:50 -0800611 outbound_video->codec_id = RTCCodecStatsIDFromMidDirectionAndPayload(
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +0100612 mid, /*inbound=*/false, *video_sender_info.codec_payload_type);
hbos585a9b12017-02-07 04:59:16 -0800613 }
hbos6ded1902016-11-01 01:50:46 -0700614 outbound_video->fir_count =
615 static_cast<uint32_t>(video_sender_info.firs_rcvd);
616 outbound_video->pli_count =
617 static_cast<uint32_t>(video_sender_info.plis_rcvd);
hbos6769c492017-01-02 08:35:13 -0800618 if (video_sender_info.qp_sum)
619 outbound_video->qp_sum = *video_sender_info.qp_sum;
620 outbound_video->frames_encoded = video_sender_info.frames_encoded;
Rasmus Brandt2efae772019-06-27 14:29:34 +0200621 outbound_video->key_frames_encoded = video_sender_info.key_frames_encoded;
Henrik Boströmf71362f2019-04-08 16:14:23 +0200622 outbound_video->total_encode_time =
623 static_cast<double>(video_sender_info.total_encode_time_ms) /
624 rtc::kNumMillisecsPerSec;
Henrik Boström23aff9b2019-05-20 15:15:38 +0200625 outbound_video->total_encoded_bytes_target =
626 video_sender_info.total_encoded_bytes_target;
Eldar Rello9276e2c2020-06-10 17:53:39 +0300627 if (video_sender_info.send_frame_width > 0) {
628 outbound_video->frame_width =
629 static_cast<uint32_t>(video_sender_info.send_frame_width);
Henrik Boströma0ff50c2020-05-05 15:54:46 +0200630 }
Eldar Rello9276e2c2020-06-10 17:53:39 +0300631 if (video_sender_info.send_frame_height > 0) {
632 outbound_video->frame_height =
633 static_cast<uint32_t>(video_sender_info.send_frame_height);
634 }
635 if (video_sender_info.framerate_sent > 0) {
636 outbound_video->frames_per_second = video_sender_info.framerate_sent;
637 }
638 outbound_video->frames_sent = video_sender_info.frames_sent;
639 outbound_video->huge_frames_sent = video_sender_info.huge_frames_sent;
Henrik Boström9fe18342019-05-16 18:38:20 +0200640 outbound_video->total_packet_send_delay =
641 static_cast<double>(video_sender_info.total_packet_send_delay_ms) /
642 rtc::kNumMillisecsPerSec;
Henrik Boströmce33b6a2019-05-28 17:42:38 +0200643 outbound_video->quality_limitation_reason =
644 QualityLimitationReasonToRTCQualityLimitationReason(
645 video_sender_info.quality_limitation_reason);
Byoungchan Lee7d235352021-05-28 21:32:04 +0900646 outbound_video->quality_limitation_durations =
647 QualityLimitationDurationToRTCQualityLimitationDuration(
648 video_sender_info.quality_limitation_durations_ms);
Evan Shrubsolecc62b162019-09-09 11:26:45 +0200649 outbound_video->quality_limitation_resolution_changes =
650 video_sender_info.quality_limitation_resolution_changes;
Artem Titov880fa812021-07-30 22:30:23 +0200651 // TODO(https://crbug.com/webrtc/10529): When info's `content_info` is
Henrik Boström2e069262019-04-09 13:59:31 +0200652 // optional, support the "unspecified" value.
653 if (video_sender_info.content_type == VideoContentType::SCREENSHARE)
654 outbound_video->content_type = RTCContentType::kScreenshare;
Henrik Boström6b430862019-08-16 13:09:51 +0200655 if (!video_sender_info.encoder_implementation_name.empty()) {
656 outbound_video->encoder_implementation =
657 video_sender_info.encoder_implementation_name;
658 }
Henrik Boströma0ff50c2020-05-05 15:54:46 +0200659 if (video_sender_info.rid) {
660 outbound_video->rid = *video_sender_info.rid;
661 }
hbos6ded1902016-11-01 01:50:46 -0700662}
663
Henrik Boström883eefc2019-05-27 13:40:25 +0200664std::unique_ptr<RTCRemoteInboundRtpStreamStats>
665ProduceRemoteInboundRtpStreamStatsFromReportBlockData(
666 const ReportBlockData& report_block_data,
667 cricket::MediaType media_type,
Eldar Relloc07e9042020-07-03 11:08:07 +0300668 const std::map<std::string, RTCOutboundRTPStreamStats*>& outbound_rtps,
Henrik Boström883eefc2019-05-27 13:40:25 +0200669 const RTCStatsReport& report) {
670 const auto& report_block = report_block_data.report_block();
671 // RTCStats' timestamp generally refers to when the metric was sampled, but
672 // for "remote-[outbound/inbound]-rtp" it refers to the local time when the
673 // Report Block was received.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200674 auto remote_inbound = std::make_unique<RTCRemoteInboundRtpStreamStats>(
Henrik Boström8605fbf2019-06-24 16:44:51 +0200675 RTCRemoteInboundRtpStreamStatsIdFromSourceSsrc(media_type,
676 report_block.source_ssrc),
Henrik Boström883eefc2019-05-27 13:40:25 +0200677 /*timestamp=*/report_block_data.report_block_timestamp_utc_us());
Henrik Boström8605fbf2019-06-24 16:44:51 +0200678 remote_inbound->ssrc = report_block.source_ssrc;
Henrik Boström883eefc2019-05-27 13:40:25 +0200679 remote_inbound->kind =
680 media_type == cricket::MEDIA_TYPE_AUDIO ? "audio" : "video";
681 remote_inbound->packets_lost = report_block.packets_lost;
Di Wu86f04ad2021-02-28 23:36:03 -0800682 remote_inbound->fraction_lost =
683 static_cast<double>(report_block.fraction_lost) / (1 << 8);
Henrik Boström883eefc2019-05-27 13:40:25 +0200684 remote_inbound->round_trip_time =
685 static_cast<double>(report_block_data.last_rtt_ms()) /
686 rtc::kNumMillisecsPerSec;
Di Wu88a51b22021-03-01 11:22:06 -0800687 remote_inbound->total_round_trip_time =
688 static_cast<double>(report_block_data.sum_rtt_ms()) /
689 rtc::kNumMillisecsPerSec;
690 remote_inbound->round_trip_time_measurements =
691 report_block_data.num_rtts();
Henrik Boström883eefc2019-05-27 13:40:25 +0200692
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +0100693 std::string local_id =
694 RTCOutboundRTPStreamStatsIDFromSSRC(media_type, report_block.source_ssrc);
Artem Titov880fa812021-07-30 22:30:23 +0200695 // Look up local stat from `outbound_rtps` where the pointers are non-const.
Henrik Boström4f40fa52019-12-19 13:27:27 +0100696 auto local_id_it = outbound_rtps.find(local_id);
697 if (local_id_it != outbound_rtps.end()) {
Henrik Boström883eefc2019-05-27 13:40:25 +0200698 remote_inbound->local_id = local_id;
Henrik Boström4f40fa52019-12-19 13:27:27 +0100699 auto& outbound_rtp = *local_id_it->second;
700 outbound_rtp.remote_id = remote_inbound->id();
Henrik Boström883eefc2019-05-27 13:40:25 +0200701 // The RTP/RTCP transport is obtained from the
702 // RTCOutboundRtpStreamStats's transport.
703 const auto* transport_from_id = outbound_rtp.transport_id.is_defined()
704 ? report.Get(*outbound_rtp.transport_id)
705 : nullptr;
706 if (transport_from_id) {
707 const auto& transport = transport_from_id->cast_to<RTCTransportStats>();
708 // If RTP and RTCP are not multiplexed, there is a separate RTCP
709 // transport paired with the RTP transport, otherwise the same
710 // transport is used for RTCP and RTP.
711 remote_inbound->transport_id =
712 transport.rtcp_transport_stats_id.is_defined()
713 ? *transport.rtcp_transport_stats_id
714 : *outbound_rtp.transport_id;
715 }
716 // We're assuming the same codec is used on both ends. However if the
717 // codec is switched out on the fly we may have received a Report Block
718 // based on the previous codec and there is no way to tell which point in
719 // time the codec changed for the remote end.
720 const auto* codec_from_id = outbound_rtp.codec_id.is_defined()
721 ? report.Get(*outbound_rtp.codec_id)
722 : nullptr;
723 if (codec_from_id) {
724 remote_inbound->codec_id = *outbound_rtp.codec_id;
725 const auto& codec = codec_from_id->cast_to<RTCCodecStats>();
726 if (codec.clock_rate.is_defined()) {
727 // The Report Block jitter is expressed in RTP timestamp units
728 // (https://tools.ietf.org/html/rfc3550#section-6.4.1). To convert this
729 // to seconds we divide by the codec's clock rate.
730 remote_inbound->jitter =
731 static_cast<double>(report_block.jitter) / *codec.clock_rate;
732 }
733 }
734 }
735 return remote_inbound;
736}
737
hbos02ba2112016-10-28 05:14:53 -0700738void ProduceCertificateStatsFromSSLCertificateStats(
Jonas Olssona4d87372019-07-05 19:08:33 +0200739 int64_t timestamp_us,
740 const rtc::SSLCertificateStats& certificate_stats,
hbos02ba2112016-10-28 05:14:53 -0700741 RTCStatsReport* report) {
742 RTCCertificateStats* prev_certificate_stats = nullptr;
743 for (const rtc::SSLCertificateStats* s = &certificate_stats; s;
744 s = s->issuer.get()) {
hbos02d2a922016-12-21 01:29:05 -0800745 std::string certificate_stats_id =
746 RTCCertificateIDFromFingerprint(s->fingerprint);
747 // It is possible for the same certificate to show up multiple times, e.g.
748 // if local and remote side use the same certificate in a loopback call.
749 // If the report already contains stats for this certificate, skip it.
750 if (report->Get(certificate_stats_id)) {
751 RTC_DCHECK_EQ(s, &certificate_stats);
752 break;
753 }
Jonas Olssona4d87372019-07-05 19:08:33 +0200754 RTCCertificateStats* certificate_stats =
755 new RTCCertificateStats(certificate_stats_id, timestamp_us);
hbos02ba2112016-10-28 05:14:53 -0700756 certificate_stats->fingerprint = s->fingerprint;
757 certificate_stats->fingerprint_algorithm = s->fingerprint_algorithm;
758 certificate_stats->base64_certificate = s->base64_certificate;
759 if (prev_certificate_stats)
760 prev_certificate_stats->issuer_certificate_id = certificate_stats->id();
761 report->AddStats(std::unique_ptr<RTCCertificateStats>(certificate_stats));
762 prev_certificate_stats = certificate_stats;
763 }
764}
765
Jonas Olssona4d87372019-07-05 19:08:33 +0200766const std::string& ProduceIceCandidateStats(int64_t timestamp_us,
767 const cricket::Candidate& candidate,
768 bool is_local,
769 const std::string& transport_id,
770 RTCStatsReport* report) {
hbos02ba2112016-10-28 05:14:53 -0700771 const std::string& id = "RTCIceCandidate_" + candidate.id();
772 const RTCStats* stats = report->Get(id);
773 if (!stats) {
774 std::unique_ptr<RTCIceCandidateStats> candidate_stats;
775 if (is_local)
776 candidate_stats.reset(new RTCLocalIceCandidateStats(id, timestamp_us));
777 else
778 candidate_stats.reset(new RTCRemoteIceCandidateStats(id, timestamp_us));
hbosb4e426e2017-01-02 09:59:31 -0800779 candidate_stats->transport_id = transport_id;
Gary Liu37e489c2017-11-21 10:49:36 -0800780 if (is_local) {
781 candidate_stats->network_type =
Jonas Oreland0d13bbd2022-03-02 11:17:36 +0100782 NetworkTypeToStatsType(candidate.network_type());
Philipp Hancke21c4b1e2021-11-11 07:45:59 +0100783 const std::string& candidate_type = candidate.type();
784 const std::string& relay_protocol = candidate.relay_protocol();
Philipp Hancke05b29c72022-02-02 12:06:15 +0100785 const std::string& url = candidate.url();
Philipp Hancke21c4b1e2021-11-11 07:45:59 +0100786 if (candidate_type == cricket::RELAY_PORT_TYPE ||
787 (candidate_type == cricket::PRFLX_PORT_TYPE &&
788 !relay_protocol.empty())) {
Philipp Hancke95513752018-09-27 14:40:08 +0200789 RTC_DCHECK(relay_protocol.compare("udp") == 0 ||
790 relay_protocol.compare("tcp") == 0 ||
791 relay_protocol.compare("tls") == 0);
792 candidate_stats->relay_protocol = relay_protocol;
Philipp Hancke05b29c72022-02-02 12:06:15 +0100793 if (!url.empty()) {
794 candidate_stats->url = url;
795 }
796 } else if (candidate_type == cricket::STUN_PORT_TYPE) {
797 if (!url.empty()) {
798 candidate_stats->url = url;
799 }
Philipp Hancke95513752018-09-27 14:40:08 +0200800 }
Jonas Oreland0d13bbd2022-03-02 11:17:36 +0100801 if (candidate.network_type() == rtc::ADAPTER_TYPE_VPN) {
802 candidate_stats->vpn = true;
803 candidate_stats->network_adapter_type =
804 std::string(NetworkTypeToStatsNetworkAdapterType(
805 candidate.underlying_type_for_vpn()));
806 } else {
807 candidate_stats->vpn = false;
808 candidate_stats->network_adapter_type = std::string(
809 NetworkTypeToStatsNetworkAdapterType(candidate.network_type()));
810 }
Gary Liu37e489c2017-11-21 10:49:36 -0800811 } else {
812 // We don't expect to know the adapter type of remote candidates.
813 RTC_DCHECK_EQ(rtc::ADAPTER_TYPE_UNKNOWN, candidate.network_type());
814 }
hbos02ba2112016-10-28 05:14:53 -0700815 candidate_stats->ip = candidate.address().ipaddr().ToString();
Philipp Hanckea9ba4502021-03-22 13:22:54 +0100816 candidate_stats->address = candidate.address().ipaddr().ToString();
hbos02ba2112016-10-28 05:14:53 -0700817 candidate_stats->port = static_cast<int32_t>(candidate.address().port());
818 candidate_stats->protocol = candidate.protocol();
Jonas Olssona4d87372019-07-05 19:08:33 +0200819 candidate_stats->candidate_type =
820 CandidateTypeToRTCIceCandidateType(candidate.type());
hbos02ba2112016-10-28 05:14:53 -0700821 candidate_stats->priority = static_cast<int32_t>(candidate.priority());
822
823 stats = candidate_stats.get();
824 report->AddStats(std::move(candidate_stats));
825 }
826 RTC_DCHECK_EQ(stats->type(), is_local ? RTCLocalIceCandidateStats::kType
827 : RTCRemoteIceCandidateStats::kType);
828 return stats->id();
829}
830
Taylor Brandstetter64851c02021-06-24 13:32:50 -0700831template <typename StatsType>
832void SetAudioProcessingStats(StatsType* stats,
833 const AudioProcessingStats& apm_stats) {
834 if (apm_stats.echo_return_loss) {
835 stats->echo_return_loss = *apm_stats.echo_return_loss;
836 }
837 if (apm_stats.echo_return_loss_enhancement) {
838 stats->echo_return_loss_enhancement =
839 *apm_stats.echo_return_loss_enhancement;
840 }
841}
842
hbos9e302742017-01-20 02:47:10 -0800843std::unique_ptr<RTCMediaStreamTrackStats>
844ProduceMediaStreamTrackStatsFromVoiceSenderInfo(
845 int64_t timestamp_us,
Taylor Brandstetter64851c02021-06-24 13:32:50 -0700846 AudioTrackInterface& audio_track,
Harald Alvestrandc72af932018-01-11 17:18:19 +0100847 const cricket::VoiceSenderInfo& voice_sender_info,
848 int attachment_id) {
hbos9e302742017-01-20 02:47:10 -0800849 std::unique_ptr<RTCMediaStreamTrackStats> audio_track_stats(
850 new RTCMediaStreamTrackStats(
Harald Alvestranda3dab842018-01-14 09:18:58 +0100851 RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(kSender,
852 attachment_id),
Harald Alvestrandc72af932018-01-11 17:18:19 +0100853 timestamp_us, RTCMediaStreamTrackKind::kAudio));
hbos9e302742017-01-20 02:47:10 -0800854 SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
855 audio_track, audio_track_stats.get());
Henrik Boström646fda02019-05-22 15:49:42 +0200856 audio_track_stats->media_source_id =
857 RTCMediaSourceStatsIDFromKindAndAttachment(cricket::MEDIA_TYPE_AUDIO,
858 attachment_id);
hbos9e302742017-01-20 02:47:10 -0800859 audio_track_stats->remote_source = false;
860 audio_track_stats->detached = false;
Taylor Brandstetter64851c02021-06-24 13:32:50 -0700861 // Audio processor may be attached to either the track or the send
862 // stream, so look in both places.
863 SetAudioProcessingStats(audio_track_stats.get(),
864 voice_sender_info.apm_statistics);
865 auto audio_processor(audio_track.GetAudioProcessor());
866 if (audio_processor.get()) {
Artem Titov880fa812021-07-30 22:30:23 +0200867 // The `has_remote_tracks` argument is obsolete; makes no difference if it's
Taylor Brandstetter64851c02021-06-24 13:32:50 -0700868 // set to true or false.
869 AudioProcessorInterface::AudioProcessorStatistics ap_stats =
870 audio_processor->GetStats(/*has_remote_tracks=*/false);
871 SetAudioProcessingStats(audio_track_stats.get(), ap_stats.apm_statistics);
hbos9e302742017-01-20 02:47:10 -0800872 }
873 return audio_track_stats;
874}
875
876std::unique_ptr<RTCMediaStreamTrackStats>
877ProduceMediaStreamTrackStatsFromVoiceReceiverInfo(
878 int64_t timestamp_us,
879 const AudioTrackInterface& audio_track,
Harald Alvestrandc72af932018-01-11 17:18:19 +0100880 const cricket::VoiceReceiverInfo& voice_receiver_info,
881 int attachment_id) {
882 // Since receiver tracks can't be reattached, we use the SSRC as
883 // an attachment identifier.
hbos9e302742017-01-20 02:47:10 -0800884 std::unique_ptr<RTCMediaStreamTrackStats> audio_track_stats(
885 new RTCMediaStreamTrackStats(
Harald Alvestranda3dab842018-01-14 09:18:58 +0100886 RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(kReceiver,
887 attachment_id),
Harald Alvestrandc72af932018-01-11 17:18:19 +0100888 timestamp_us, RTCMediaStreamTrackKind::kAudio));
hbos9e302742017-01-20 02:47:10 -0800889 SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
890 audio_track, audio_track_stats.get());
891 audio_track_stats->remote_source = true;
892 audio_track_stats->detached = false;
893 if (voice_receiver_info.audio_level >= 0) {
Jonas Olssona4d87372019-07-05 19:08:33 +0200894 audio_track_stats->audio_level =
895 DoubleAudioLevelFromIntAudioLevel(voice_receiver_info.audio_level);
hbos9e302742017-01-20 02:47:10 -0800896 }
Gustaf Ullbergb0a02072017-10-02 12:00:34 +0200897 audio_track_stats->jitter_buffer_delay =
898 voice_receiver_info.jitter_buffer_delay_seconds;
Chen Xing0acffb52019-01-15 15:46:29 +0100899 audio_track_stats->jitter_buffer_emitted_count =
900 voice_receiver_info.jitter_buffer_emitted_count;
Ivo Creusen8d8ffdb2019-04-30 09:45:21 +0200901 audio_track_stats->inserted_samples_for_deceleration =
902 voice_receiver_info.inserted_samples_for_deceleration;
903 audio_track_stats->removed_samples_for_acceleration =
904 voice_receiver_info.removed_samples_for_acceleration;
zsteine76bd3a2017-07-14 12:17:49 -0700905 audio_track_stats->total_audio_energy =
906 voice_receiver_info.total_output_energy;
Steve Anton2dbc69f2017-08-24 17:15:13 -0700907 audio_track_stats->total_samples_received =
908 voice_receiver_info.total_samples_received;
zsteine76bd3a2017-07-14 12:17:49 -0700909 audio_track_stats->total_samples_duration =
910 voice_receiver_info.total_output_duration;
Steve Anton2dbc69f2017-08-24 17:15:13 -0700911 audio_track_stats->concealed_samples = voice_receiver_info.concealed_samples;
Ivo Creusen8d8ffdb2019-04-30 09:45:21 +0200912 audio_track_stats->silent_concealed_samples =
913 voice_receiver_info.silent_concealed_samples;
Gustaf Ullberg9a2e9062017-09-18 09:28:20 +0200914 audio_track_stats->concealment_events =
915 voice_receiver_info.concealment_events;
Ruslan Burakov8af88962018-11-22 17:21:10 +0100916 audio_track_stats->jitter_buffer_flushes =
917 voice_receiver_info.jitter_buffer_flushes;
Jakob Ivarsson352ce5c2018-11-27 12:52:16 +0100918 audio_track_stats->delayed_packet_outage_samples =
919 voice_receiver_info.delayed_packet_outage_samples;
Jakob Ivarsson232b3fd2019-03-06 09:18:40 +0100920 audio_track_stats->relative_packet_arrival_delay =
921 voice_receiver_info.relative_packet_arrival_delay_seconds;
Artem Titove618cc92020-03-11 11:18:54 +0100922 audio_track_stats->jitter_buffer_target_delay =
923 voice_receiver_info.jitter_buffer_target_delay_seconds;
Henrik Lundin44125fa2019-04-29 17:00:46 +0200924 audio_track_stats->interruption_count =
925 voice_receiver_info.interruption_count >= 0
926 ? voice_receiver_info.interruption_count
927 : 0;
928 audio_track_stats->total_interruption_duration =
929 static_cast<double>(voice_receiver_info.total_interruption_duration_ms) /
930 rtc::kNumMillisecsPerSec;
hbos9e302742017-01-20 02:47:10 -0800931 return audio_track_stats;
932}
933
934std::unique_ptr<RTCMediaStreamTrackStats>
935ProduceMediaStreamTrackStatsFromVideoSenderInfo(
936 int64_t timestamp_us,
937 const VideoTrackInterface& video_track,
Harald Alvestrandc72af932018-01-11 17:18:19 +0100938 const cricket::VideoSenderInfo& video_sender_info,
939 int attachment_id) {
hbos9e302742017-01-20 02:47:10 -0800940 std::unique_ptr<RTCMediaStreamTrackStats> video_track_stats(
941 new RTCMediaStreamTrackStats(
Harald Alvestranda3dab842018-01-14 09:18:58 +0100942 RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(kSender,
Harald Alvestranda3dab842018-01-14 09:18:58 +0100943 attachment_id),
Harald Alvestrandc72af932018-01-11 17:18:19 +0100944 timestamp_us, RTCMediaStreamTrackKind::kVideo));
hbos9e302742017-01-20 02:47:10 -0800945 SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
946 video_track, video_track_stats.get());
Henrik Boström646fda02019-05-22 15:49:42 +0200947 video_track_stats->media_source_id =
948 RTCMediaSourceStatsIDFromKindAndAttachment(cricket::MEDIA_TYPE_VIDEO,
949 attachment_id);
hbos9e302742017-01-20 02:47:10 -0800950 video_track_stats->remote_source = false;
951 video_track_stats->detached = false;
Jonas Olssona4d87372019-07-05 19:08:33 +0200952 video_track_stats->frame_width =
953 static_cast<uint32_t>(video_sender_info.send_frame_width);
954 video_track_stats->frame_height =
955 static_cast<uint32_t>(video_sender_info.send_frame_height);
hbosfefe0762017-01-20 06:14:25 -0800956 // TODO(hbos): Will reduce this by frames dropped due to congestion control
Harald Alvestrand89061872018-01-02 14:08:34 +0100957 // when available. https://crbug.com/659137
hbosfefe0762017-01-20 06:14:25 -0800958 video_track_stats->frames_sent = video_sender_info.frames_encoded;
Ilya Nikolaevskiy70473fc2018-02-28 16:35:03 +0100959 video_track_stats->huge_frames_sent = video_sender_info.huge_frames_sent;
hbos9e302742017-01-20 02:47:10 -0800960 return video_track_stats;
961}
962
963std::unique_ptr<RTCMediaStreamTrackStats>
964ProduceMediaStreamTrackStatsFromVideoReceiverInfo(
965 int64_t timestamp_us,
966 const VideoTrackInterface& video_track,
Harald Alvestrandc72af932018-01-11 17:18:19 +0100967 const cricket::VideoReceiverInfo& video_receiver_info,
968 int attachment_id) {
hbos9e302742017-01-20 02:47:10 -0800969 std::unique_ptr<RTCMediaStreamTrackStats> video_track_stats(
970 new RTCMediaStreamTrackStats(
Harald Alvestranda3dab842018-01-14 09:18:58 +0100971 RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(kReceiver,
972
973 attachment_id),
Harald Alvestrandc72af932018-01-11 17:18:19 +0100974 timestamp_us, RTCMediaStreamTrackKind::kVideo));
hbos9e302742017-01-20 02:47:10 -0800975 SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
976 video_track, video_track_stats.get());
977 video_track_stats->remote_source = true;
978 video_track_stats->detached = false;
979 if (video_receiver_info.frame_width > 0 &&
980 video_receiver_info.frame_height > 0) {
Jonas Olssona4d87372019-07-05 19:08:33 +0200981 video_track_stats->frame_width =
982 static_cast<uint32_t>(video_receiver_info.frame_width);
983 video_track_stats->frame_height =
984 static_cast<uint32_t>(video_receiver_info.frame_height);
hbos9e302742017-01-20 02:47:10 -0800985 }
Guido Urdaneta67378412019-05-28 17:38:08 +0200986 video_track_stats->jitter_buffer_delay =
987 video_receiver_info.jitter_buffer_delay_seconds;
988 video_track_stats->jitter_buffer_emitted_count =
989 video_receiver_info.jitter_buffer_emitted_count;
hbos42f6d2f2017-01-20 03:56:50 -0800990 video_track_stats->frames_received = video_receiver_info.frames_received;
hbosf64941f2017-01-20 07:39:09 -0800991 // TODO(hbos): When we support receiving simulcast, this should be the total
992 // number of frames correctly decoded, independent of which SSRC it was
993 // received from. Since we don't support that, this is correct and is the same
Harald Alvestrand89061872018-01-02 14:08:34 +0100994 // value as "RTCInboundRTPStreamStats.framesDecoded". https://crbug.com/659137
hbosf64941f2017-01-20 07:39:09 -0800995 video_track_stats->frames_decoded = video_receiver_info.frames_decoded;
Johannes Kron0c141c52019-08-26 15:04:43 +0200996 video_track_stats->frames_dropped = video_receiver_info.frames_dropped;
Sergey Silkin02371062019-01-31 16:45:42 +0100997 video_track_stats->freeze_count = video_receiver_info.freeze_count;
998 video_track_stats->pause_count = video_receiver_info.pause_count;
999 video_track_stats->total_freezes_duration =
1000 static_cast<double>(video_receiver_info.total_freezes_duration_ms) /
1001 rtc::kNumMillisecsPerSec;
1002 video_track_stats->total_pauses_duration =
1003 static_cast<double>(video_receiver_info.total_pauses_duration_ms) /
1004 rtc::kNumMillisecsPerSec;
1005 video_track_stats->total_frames_duration =
1006 static_cast<double>(video_receiver_info.total_frames_duration_ms) /
1007 rtc::kNumMillisecsPerSec;
1008 video_track_stats->sum_squared_frame_durations =
1009 video_receiver_info.sum_squared_frame_durations;
1010
hbos9e302742017-01-20 02:47:10 -08001011 return video_track_stats;
1012}
1013
Harald Alvestrand89061872018-01-02 14:08:34 +01001014void ProduceSenderMediaTrackStats(
1015 int64_t timestamp_us,
1016 const TrackMediaInfoMap& track_media_info_map,
Steve Anton57858b32018-02-15 15:19:50 -08001017 std::vector<rtc::scoped_refptr<RtpSenderInternal>> senders,
Harald Alvestrand89061872018-01-02 14:08:34 +01001018 RTCStatsReport* report) {
1019 // This function iterates over the senders to generate outgoing track stats.
1020
1021 // TODO(hbos): Return stats of detached tracks. We have to perform stats
1022 // gathering at the time of detachment to get accurate stats and timestamps.
1023 // https://crbug.com/659137
Mirko Bonadei739baf02019-01-27 17:29:42 +01001024 for (const auto& sender : senders) {
Harald Alvestrand89061872018-01-02 14:08:34 +01001025 if (sender->media_type() == cricket::MEDIA_TYPE_AUDIO) {
1026 AudioTrackInterface* track =
1027 static_cast<AudioTrackInterface*>(sender->track().get());
1028 if (!track)
1029 continue;
Harald Alvestrandb8e12012018-01-23 15:28:16 +01001030 cricket::VoiceSenderInfo null_sender_info;
1031 const cricket::VoiceSenderInfo* voice_sender_info = &null_sender_info;
1032 // TODO(hta): Checking on ssrc is not proper. There should be a way
1033 // to see from a sender whether it's connected or not.
1034 // Related to https://crbug.com/8694 (using ssrc 0 to indicate "none")
Steve Anton57858b32018-02-15 15:19:50 -08001035 if (sender->ssrc() != 0) {
Harald Alvestrand76d29522018-01-30 14:43:29 +01001036 // When pc.close is called, sender info is discarded, so
1037 // we generate zeroes instead. Bug: It should be retained.
1038 // https://crbug.com/807174
Steve Anton57858b32018-02-15 15:19:50 -08001039 const cricket::VoiceSenderInfo* sender_info =
Harald Alvestrandb8e12012018-01-23 15:28:16 +01001040 track_media_info_map.GetVoiceSenderInfoBySsrc(sender->ssrc());
Harald Alvestrand76d29522018-01-30 14:43:29 +01001041 if (sender_info) {
1042 voice_sender_info = sender_info;
1043 } else {
Tommi19015512022-02-02 11:49:35 +01001044 RTC_DLOG(LS_INFO)
Harald Alvestrand76d29522018-01-30 14:43:29 +01001045 << "RTCStatsCollector: No voice sender info for sender with ssrc "
1046 << sender->ssrc();
1047 }
Harald Alvestrandb8e12012018-01-23 15:28:16 +01001048 }
Harald Alvestrand89061872018-01-02 14:08:34 +01001049 std::unique_ptr<RTCMediaStreamTrackStats> audio_track_stats =
Harald Alvestrandc72af932018-01-11 17:18:19 +01001050 ProduceMediaStreamTrackStatsFromVoiceSenderInfo(
1051 timestamp_us, *track, *voice_sender_info, sender->AttachmentId());
Harald Alvestrand89061872018-01-02 14:08:34 +01001052 report->AddStats(std::move(audio_track_stats));
1053 } else if (sender->media_type() == cricket::MEDIA_TYPE_VIDEO) {
1054 VideoTrackInterface* track =
1055 static_cast<VideoTrackInterface*>(sender->track().get());
1056 if (!track)
1057 continue;
Harald Alvestrandb8e12012018-01-23 15:28:16 +01001058 cricket::VideoSenderInfo null_sender_info;
1059 const cricket::VideoSenderInfo* video_sender_info = &null_sender_info;
1060 // TODO(hta): Check on state not ssrc when state is available
Harald Alvestrand76d29522018-01-30 14:43:29 +01001061 // Related to https://bugs.webrtc.org/8694 (using ssrc 0 to indicate
1062 // "none")
Steve Anton57858b32018-02-15 15:19:50 -08001063 if (sender->ssrc() != 0) {
Harald Alvestrand76d29522018-01-30 14:43:29 +01001064 // When pc.close is called, sender info is discarded, so
1065 // we generate zeroes instead. Bug: It should be retained.
1066 // https://crbug.com/807174
Steve Anton57858b32018-02-15 15:19:50 -08001067 const cricket::VideoSenderInfo* sender_info =
Harald Alvestrandb8e12012018-01-23 15:28:16 +01001068 track_media_info_map.GetVideoSenderInfoBySsrc(sender->ssrc());
Harald Alvestrand76d29522018-01-30 14:43:29 +01001069 if (sender_info) {
1070 video_sender_info = sender_info;
1071 } else {
Tommi19015512022-02-02 11:49:35 +01001072 RTC_DLOG(LS_INFO)
1073 << "No video sender info for sender with ssrc " << sender->ssrc();
Harald Alvestrand76d29522018-01-30 14:43:29 +01001074 }
1075 }
Harald Alvestrand89061872018-01-02 14:08:34 +01001076 std::unique_ptr<RTCMediaStreamTrackStats> video_track_stats =
Harald Alvestrandc72af932018-01-11 17:18:19 +01001077 ProduceMediaStreamTrackStatsFromVideoSenderInfo(
1078 timestamp_us, *track, *video_sender_info, sender->AttachmentId());
Harald Alvestrand89061872018-01-02 14:08:34 +01001079 report->AddStats(std::move(video_track_stats));
1080 } else {
Artem Titovd3251962021-11-15 16:57:07 +01001081 RTC_DCHECK_NOTREACHED();
Harald Alvestrand89061872018-01-02 14:08:34 +01001082 }
1083 }
1084}
1085
1086void ProduceReceiverMediaTrackStats(
1087 int64_t timestamp_us,
1088 const TrackMediaInfoMap& track_media_info_map,
Steve Anton57858b32018-02-15 15:19:50 -08001089 std::vector<rtc::scoped_refptr<RtpReceiverInternal>> receivers,
Harald Alvestrand89061872018-01-02 14:08:34 +01001090 RTCStatsReport* report) {
1091 // This function iterates over the receivers to find the remote tracks.
Mirko Bonadei739baf02019-01-27 17:29:42 +01001092 for (const auto& receiver : receivers) {
Harald Alvestrand89061872018-01-02 14:08:34 +01001093 if (receiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
1094 AudioTrackInterface* track =
1095 static_cast<AudioTrackInterface*>(receiver->track().get());
1096 const cricket::VoiceReceiverInfo* voice_receiver_info =
1097 track_media_info_map.GetVoiceReceiverInfo(*track);
1098 if (!voice_receiver_info) {
1099 continue;
1100 }
1101 std::unique_ptr<RTCMediaStreamTrackStats> audio_track_stats =
1102 ProduceMediaStreamTrackStatsFromVoiceReceiverInfo(
Harald Alvestrandc72af932018-01-11 17:18:19 +01001103 timestamp_us, *track, *voice_receiver_info,
1104 receiver->AttachmentId());
Harald Alvestrand89061872018-01-02 14:08:34 +01001105 report->AddStats(std::move(audio_track_stats));
1106 } else if (receiver->media_type() == cricket::MEDIA_TYPE_VIDEO) {
1107 VideoTrackInterface* track =
1108 static_cast<VideoTrackInterface*>(receiver->track().get());
1109 const cricket::VideoReceiverInfo* video_receiver_info =
1110 track_media_info_map.GetVideoReceiverInfo(*track);
1111 if (!video_receiver_info) {
1112 continue;
1113 }
1114 std::unique_ptr<RTCMediaStreamTrackStats> video_track_stats =
1115 ProduceMediaStreamTrackStatsFromVideoReceiverInfo(
Harald Alvestrandc72af932018-01-11 17:18:19 +01001116 timestamp_us, *track, *video_receiver_info,
1117 receiver->AttachmentId());
Harald Alvestrand89061872018-01-02 14:08:34 +01001118 report->AddStats(std::move(video_track_stats));
1119 } else {
Artem Titovd3251962021-11-15 16:57:07 +01001120 RTC_DCHECK_NOTREACHED();
Harald Alvestrand89061872018-01-02 14:08:34 +01001121 }
1122 }
1123}
1124
Henrik Boström5b3541f2018-03-19 13:52:56 +01001125rtc::scoped_refptr<RTCStatsReport> CreateReportFilteredBySelector(
1126 bool filter_by_sender_selector,
1127 rtc::scoped_refptr<const RTCStatsReport> report,
1128 rtc::scoped_refptr<RtpSenderInternal> sender_selector,
1129 rtc::scoped_refptr<RtpReceiverInternal> receiver_selector) {
1130 std::vector<std::string> rtpstream_ids;
1131 if (filter_by_sender_selector) {
1132 // Filter mode: RTCStatsCollector::RequestInfo::kSenderSelector
1133 if (sender_selector) {
1134 // Find outbound-rtp(s) of the sender, i.e. the outbound-rtp(s) that
1135 // reference the sender stats.
1136 // Because we do not implement sender stats, we look at outbound-rtp(s)
1137 // that reference the track attachment stats for the sender instead.
1138 std::string track_id =
1139 RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
1140 kSender, sender_selector->AttachmentId());
1141 for (const auto& stats : *report) {
1142 if (stats.type() != RTCOutboundRTPStreamStats::kType)
1143 continue;
1144 const auto& outbound_rtp = stats.cast_to<RTCOutboundRTPStreamStats>();
1145 if (outbound_rtp.track_id.is_defined() &&
1146 *outbound_rtp.track_id == track_id) {
1147 rtpstream_ids.push_back(outbound_rtp.id());
1148 }
1149 }
1150 }
1151 } else {
1152 // Filter mode: RTCStatsCollector::RequestInfo::kReceiverSelector
1153 if (receiver_selector) {
1154 // Find inbound-rtp(s) of the receiver, i.e. the inbound-rtp(s) that
1155 // reference the receiver stats.
1156 // Because we do not implement receiver stats, we look at inbound-rtp(s)
1157 // that reference the track attachment stats for the receiver instead.
1158 std::string track_id =
1159 RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
1160 kReceiver, receiver_selector->AttachmentId());
1161 for (const auto& stats : *report) {
1162 if (stats.type() != RTCInboundRTPStreamStats::kType)
1163 continue;
1164 const auto& inbound_rtp = stats.cast_to<RTCInboundRTPStreamStats>();
1165 if (inbound_rtp.track_id.is_defined() &&
1166 *inbound_rtp.track_id == track_id) {
1167 rtpstream_ids.push_back(inbound_rtp.id());
1168 }
1169 }
1170 }
1171 }
1172 if (rtpstream_ids.empty())
1173 return RTCStatsReport::Create(report->timestamp_us());
1174 return TakeReferencedStats(report->Copy(), rtpstream_ids);
1175}
1176
hboscc555c52016-10-18 12:48:31 -07001177} // namespace
1178
Henrik Boström5b3541f2018-03-19 13:52:56 +01001179RTCStatsCollector::RequestInfo::RequestInfo(
1180 rtc::scoped_refptr<RTCStatsCollectorCallback> callback)
1181 : RequestInfo(FilterMode::kAll, std::move(callback), nullptr, nullptr) {}
1182
1183RTCStatsCollector::RequestInfo::RequestInfo(
1184 rtc::scoped_refptr<RtpSenderInternal> selector,
1185 rtc::scoped_refptr<RTCStatsCollectorCallback> callback)
1186 : RequestInfo(FilterMode::kSenderSelector,
1187 std::move(callback),
1188 std::move(selector),
1189 nullptr) {}
1190
1191RTCStatsCollector::RequestInfo::RequestInfo(
1192 rtc::scoped_refptr<RtpReceiverInternal> selector,
1193 rtc::scoped_refptr<RTCStatsCollectorCallback> callback)
1194 : RequestInfo(FilterMode::kReceiverSelector,
1195 std::move(callback),
1196 nullptr,
1197 std::move(selector)) {}
1198
1199RTCStatsCollector::RequestInfo::RequestInfo(
1200 RTCStatsCollector::RequestInfo::FilterMode filter_mode,
1201 rtc::scoped_refptr<RTCStatsCollectorCallback> callback,
1202 rtc::scoped_refptr<RtpSenderInternal> sender_selector,
1203 rtc::scoped_refptr<RtpReceiverInternal> receiver_selector)
1204 : filter_mode_(filter_mode),
1205 callback_(std::move(callback)),
1206 sender_selector_(std::move(sender_selector)),
1207 receiver_selector_(std::move(receiver_selector)) {
1208 RTC_DCHECK(callback_);
1209 RTC_DCHECK(!sender_selector_ || !receiver_selector_);
1210}
1211
hbosc82f2e12016-09-05 01:36:50 -07001212rtc::scoped_refptr<RTCStatsCollector> RTCStatsCollector::Create(
Steve Anton2d8609c2018-01-23 16:38:46 -08001213 PeerConnectionInternal* pc,
1214 int64_t cache_lifetime_us) {
Tommi87f70902021-04-27 14:43:08 +02001215 return rtc::make_ref_counted<RTCStatsCollector>(pc, cache_lifetime_us);
hbosc82f2e12016-09-05 01:36:50 -07001216}
1217
Steve Anton2d8609c2018-01-23 16:38:46 -08001218RTCStatsCollector::RTCStatsCollector(PeerConnectionInternal* pc,
hbosc82f2e12016-09-05 01:36:50 -07001219 int64_t cache_lifetime_us)
hbosd565b732016-08-30 14:04:35 -07001220 : pc_(pc),
Steve Anton978b8762017-09-29 12:15:02 -07001221 signaling_thread_(pc->signaling_thread()),
1222 worker_thread_(pc->worker_thread()),
1223 network_thread_(pc->network_thread()),
hbosc82f2e12016-09-05 01:36:50 -07001224 num_pending_partial_reports_(0),
1225 partial_report_timestamp_us_(0),
Henrik Boström40b030e2019-02-28 09:49:31 +01001226 network_report_event_(true /* manual_reset */,
1227 true /* initially_signaled */),
hbos0e6758d2016-08-31 07:57:36 -07001228 cache_timestamp_us_(0),
1229 cache_lifetime_us_(cache_lifetime_us) {
hbosd565b732016-08-30 14:04:35 -07001230 RTC_DCHECK(pc_);
hbosc82f2e12016-09-05 01:36:50 -07001231 RTC_DCHECK(signaling_thread_);
1232 RTC_DCHECK(worker_thread_);
1233 RTC_DCHECK(network_thread_);
hbos0e6758d2016-08-31 07:57:36 -07001234 RTC_DCHECK_GE(cache_lifetime_us_, 0);
Mirko Bonadeie0bc8d22022-02-08 07:41:25 +00001235 pc_->SignalSctpDataChannelCreated().connect(
1236 this, &RTCStatsCollector::OnSctpDataChannelCreated);
hbosd565b732016-08-30 14:04:35 -07001237}
1238
hbosb78306a2016-12-19 05:06:57 -08001239RTCStatsCollector::~RTCStatsCollector() {
1240 RTC_DCHECK_EQ(num_pending_partial_reports_, 0);
1241}
1242
hbosc82f2e12016-09-05 01:36:50 -07001243void RTCStatsCollector::GetStatsReport(
1244 rtc::scoped_refptr<RTCStatsCollectorCallback> callback) {
Henrik Boström5b3541f2018-03-19 13:52:56 +01001245 GetStatsReportInternal(RequestInfo(std::move(callback)));
1246}
1247
1248void RTCStatsCollector::GetStatsReport(
1249 rtc::scoped_refptr<RtpSenderInternal> selector,
1250 rtc::scoped_refptr<RTCStatsCollectorCallback> callback) {
1251 GetStatsReportInternal(RequestInfo(std::move(selector), std::move(callback)));
1252}
1253
1254void RTCStatsCollector::GetStatsReport(
1255 rtc::scoped_refptr<RtpReceiverInternal> selector,
1256 rtc::scoped_refptr<RTCStatsCollectorCallback> callback) {
1257 GetStatsReportInternal(RequestInfo(std::move(selector), std::move(callback)));
1258}
1259
1260void RTCStatsCollector::GetStatsReportInternal(
1261 RTCStatsCollector::RequestInfo request) {
Tomas Gunnarsson67b1fa22021-04-08 15:18:05 +02001262 RTC_DCHECK_RUN_ON(signaling_thread_);
Henrik Boström5b3541f2018-03-19 13:52:56 +01001263 requests_.push_back(std::move(request));
hbosc82f2e12016-09-05 01:36:50 -07001264
hbos0e6758d2016-08-31 07:57:36 -07001265 // "Now" using a monotonically increasing timer.
1266 int64_t cache_now_us = rtc::TimeMicros();
1267 if (cached_report_ &&
1268 cache_now_us - cache_timestamp_us_ <= cache_lifetime_us_) {
Taylor Brandstetter25e022f2018-03-08 09:53:47 -08001269 // We have a fresh cached report to deliver. Deliver asynchronously, since
1270 // the caller may not be expecting a synchronous callback, and it avoids
1271 // reentrancy problems.
Henrik Boström5b3541f2018-03-19 13:52:56 +01001272 std::vector<RequestInfo> requests;
1273 requests.swap(requests_);
Niels Möller4bab23f2021-01-18 09:24:33 +01001274
1275 // Task subclass to take ownership of the requests.
1276 // TODO(nisse): Delete when we can use C++14, and do lambda capture with
1277 // std::move.
1278 class DeliveryTask : public QueuedTask {
1279 public:
1280 DeliveryTask(rtc::scoped_refptr<RTCStatsCollector> collector,
1281 rtc::scoped_refptr<const RTCStatsReport> cached_report,
1282 std::vector<RequestInfo> requests)
1283 : collector_(collector),
1284 cached_report_(cached_report),
1285 requests_(std::move(requests)) {}
1286 bool Run() override {
1287 collector_->DeliverCachedReport(cached_report_, std::move(requests_));
1288 return true;
1289 }
1290
1291 private:
1292 rtc::scoped_refptr<RTCStatsCollector> collector_;
1293 rtc::scoped_refptr<const RTCStatsReport> cached_report_;
1294 std::vector<RequestInfo> requests_;
1295 };
1296 signaling_thread_->PostTask(std::make_unique<DeliveryTask>(
Niels Möllere7cc8832022-01-04 15:20:03 +01001297 rtc::scoped_refptr<RTCStatsCollector>(this), cached_report_,
1298 std::move(requests)));
hbosc82f2e12016-09-05 01:36:50 -07001299 } else if (!num_pending_partial_reports_) {
1300 // Only start gathering stats if we're not already gathering stats. In the
Artem Titov880fa812021-07-30 22:30:23 +02001301 // case of already gathering stats, `callback_` will be invoked when there
hbosc82f2e12016-09-05 01:36:50 -07001302 // are no more pending partial reports.
1303
1304 // "Now" using a system clock, relative to the UNIX epoch (Jan 1, 1970,
1305 // UTC), in microseconds. The system clock could be modified and is not
1306 // necessarily monotonically increasing.
nissecdf37a92016-09-13 23:41:47 -07001307 int64_t timestamp_us = rtc::TimeUTCMicros();
hbosc82f2e12016-09-05 01:36:50 -07001308
hbosf415f8a2017-01-02 04:28:51 -08001309 num_pending_partial_reports_ = 2;
hbosc82f2e12016-09-05 01:36:50 -07001310 partial_report_timestamp_us_ = cache_now_us;
hbosdf6075a2016-12-19 04:58:02 -08001311
Artem Titov880fa812021-07-30 22:30:23 +02001312 // Prepare `transceiver_stats_infos_` and `call_stats_` for use in
1313 // `ProducePartialResultsOnNetworkThread` and
1314 // `ProducePartialResultsOnSignalingThread`.
Tomas Gunnarssonbfd9ba82021-04-18 11:55:57 +02001315 PrepareTransceiverStatsInfosAndCallStats_s_w_n();
Artem Titov880fa812021-07-30 22:30:23 +02001316 // Don't touch `network_report_` on the signaling thread until
Henrik Boström40b030e2019-02-28 09:49:31 +01001317 // ProducePartialResultsOnNetworkThread() has signaled the
Artem Titov880fa812021-07-30 22:30:23 +02001318 // `network_report_event_`.
Henrik Boström40b030e2019-02-28 09:49:31 +01001319 network_report_event_.Reset();
Niels Möller4bab23f2021-01-18 09:24:33 +01001320 rtc::scoped_refptr<RTCStatsCollector> collector(this);
Tomas Gunnarssonbfd9ba82021-04-18 11:55:57 +02001321 network_thread_->PostTask(
Tomas Gunnarssonbfd9ba82021-04-18 11:55:57 +02001322 [collector, sctp_transport_name = pc_->sctp_transport_name(),
1323 timestamp_us]() mutable {
1324 collector->ProducePartialResultsOnNetworkThread(
1325 timestamp_us, std::move(sctp_transport_name));
1326 });
hbosf415f8a2017-01-02 04:28:51 -08001327 ProducePartialResultsOnSignalingThread(timestamp_us);
hbos0e6758d2016-08-31 07:57:36 -07001328 }
hbosd565b732016-08-30 14:04:35 -07001329}
1330
1331void RTCStatsCollector::ClearCachedStatsReport() {
Tomas Gunnarsson67b1fa22021-04-08 15:18:05 +02001332 RTC_DCHECK_RUN_ON(signaling_thread_);
hbosd565b732016-08-30 14:04:35 -07001333 cached_report_ = nullptr;
1334}
1335
hbosb78306a2016-12-19 05:06:57 -08001336void RTCStatsCollector::WaitForPendingRequest() {
Tomas Gunnarsson67b1fa22021-04-08 15:18:05 +02001337 RTC_DCHECK_RUN_ON(signaling_thread_);
Artem Titov880fa812021-07-30 22:30:23 +02001338 // If a request is pending, blocks until the `network_report_event_` is
Henrik Boström40b030e2019-02-28 09:49:31 +01001339 // signaled and then delivers the result. Otherwise this is a NO-OP.
1340 MergeNetworkReport_s();
hbosb78306a2016-12-19 05:06:57 -08001341}
1342
hbosc82f2e12016-09-05 01:36:50 -07001343void RTCStatsCollector::ProducePartialResultsOnSignalingThread(
1344 int64_t timestamp_us) {
Tomas Gunnarsson67b1fa22021-04-08 15:18:05 +02001345 RTC_DCHECK_RUN_ON(signaling_thread_);
Henrik Boströme88c95e2020-07-08 11:18:50 +02001346 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1347
Henrik Boström40b030e2019-02-28 09:49:31 +01001348 partial_report_ = RTCStatsReport::Create(timestamp_us);
hbosc82f2e12016-09-05 01:36:50 -07001349
Henrik Boström40b030e2019-02-28 09:49:31 +01001350 ProducePartialResultsOnSignalingThreadImpl(timestamp_us,
1351 partial_report_.get());
hbosc82f2e12016-09-05 01:36:50 -07001352
Henrik Boström40b030e2019-02-28 09:49:31 +01001353 // ProducePartialResultsOnSignalingThread() is running synchronously on the
1354 // signaling thread, so it is always the first partial result delivered on the
1355 // signaling thread. The request is not complete until MergeNetworkReport_s()
1356 // happens; we don't have to do anything here.
1357 RTC_DCHECK_GT(num_pending_partial_reports_, 1);
1358 --num_pending_partial_reports_;
1359}
1360
1361void RTCStatsCollector::ProducePartialResultsOnSignalingThreadImpl(
1362 int64_t timestamp_us,
1363 RTCStatsReport* partial_report) {
Tomas Gunnarsson67b1fa22021-04-08 15:18:05 +02001364 RTC_DCHECK_RUN_ON(signaling_thread_);
Henrik Boströme88c95e2020-07-08 11:18:50 +02001365 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1366
Henrik Boström40b030e2019-02-28 09:49:31 +01001367 ProduceDataChannelStats_s(timestamp_us, partial_report);
1368 ProduceMediaStreamStats_s(timestamp_us, partial_report);
1369 ProduceMediaStreamTrackStats_s(timestamp_us, partial_report);
Henrik Boström646fda02019-05-22 15:49:42 +02001370 ProduceMediaSourceStats_s(timestamp_us, partial_report);
Henrik Boström40b030e2019-02-28 09:49:31 +01001371 ProducePeerConnectionStats_s(timestamp_us, partial_report);
hbosc82f2e12016-09-05 01:36:50 -07001372}
1373
hbosc82f2e12016-09-05 01:36:50 -07001374void RTCStatsCollector::ProducePartialResultsOnNetworkThread(
Tomas Gunnarssonbfd9ba82021-04-18 11:55:57 +02001375 int64_t timestamp_us,
1376 absl::optional<std::string> sctp_transport_name) {
Markus Handell518669d2021-06-07 13:30:46 +02001377 TRACE_EVENT0("webrtc",
1378 "RTCStatsCollector::ProducePartialResultsOnNetworkThread");
Tomas Gunnarsson67b1fa22021-04-08 15:18:05 +02001379 RTC_DCHECK_RUN_ON(network_thread_);
Henrik Boströme88c95e2020-07-08 11:18:50 +02001380 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1381
Artem Titov880fa812021-07-30 22:30:23 +02001382 // Touching `network_report_` on this thread is safe by this method because
1383 // `network_report_event_` is reset before this method is invoked.
Henrik Boström40b030e2019-02-28 09:49:31 +01001384 network_report_ = RTCStatsReport::Create(timestamp_us);
hbosc82f2e12016-09-05 01:36:50 -07001385
Tomas Gunnarssonbfd9ba82021-04-18 11:55:57 +02001386 std::set<std::string> transport_names;
1387 if (sctp_transport_name) {
1388 transport_names.emplace(std::move(*sctp_transport_name));
1389 }
1390
1391 for (const auto& info : transceiver_stats_infos_) {
1392 if (info.transport_name)
1393 transport_names.insert(*info.transport_name);
1394 }
1395
Steve Anton5dfde182018-02-06 10:34:40 -08001396 std::map<std::string, cricket::TransportStats> transport_stats_by_name =
Tomas Gunnarssonbfd9ba82021-04-18 11:55:57 +02001397 pc_->GetTransportStatsByNames(transport_names);
Steve Anton5dfde182018-02-06 10:34:40 -08001398 std::map<std::string, CertificateStatsPair> transport_cert_stats =
1399 PrepareTransportCertificateStats_n(transport_stats_by_name);
1400
Henrik Boström40b030e2019-02-28 09:49:31 +01001401 ProducePartialResultsOnNetworkThreadImpl(
1402 timestamp_us, transport_stats_by_name, transport_cert_stats,
1403 network_report_.get());
Mirko Bonadeica890ee2019-02-15 21:10:40 +00001404
Artem Titov880fa812021-07-30 22:30:23 +02001405 // Signal that it is now safe to touch `network_report_` on the signaling
Henrik Boström40b030e2019-02-28 09:49:31 +01001406 // thread, and post a task to merge it into the final results.
1407 network_report_event_.Set();
Niels Möller4bab23f2021-01-18 09:24:33 +01001408 rtc::scoped_refptr<RTCStatsCollector> collector(this);
Henrik Boström40b030e2019-02-28 09:49:31 +01001409 signaling_thread_->PostTask(
Henrik Boström2deee4b2022-01-20 11:58:05 +01001410 [collector] { collector->MergeNetworkReport_s(); });
Henrik Boström05d43c62019-02-15 10:23:08 +01001411}
1412
Henrik Boström40b030e2019-02-28 09:49:31 +01001413void RTCStatsCollector::ProducePartialResultsOnNetworkThreadImpl(
1414 int64_t timestamp_us,
1415 const std::map<std::string, cricket::TransportStats>&
1416 transport_stats_by_name,
1417 const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
1418 RTCStatsReport* partial_report) {
Tomas Gunnarsson67b1fa22021-04-08 15:18:05 +02001419 RTC_DCHECK_RUN_ON(network_thread_);
Henrik Boströme88c95e2020-07-08 11:18:50 +02001420 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1421
Henrik Boström40b030e2019-02-28 09:49:31 +01001422 ProduceCertificateStats_n(timestamp_us, transport_cert_stats, partial_report);
1423 ProduceCodecStats_n(timestamp_us, transceiver_stats_infos_, partial_report);
1424 ProduceIceCandidateAndPairStats_n(timestamp_us, transport_stats_by_name,
1425 call_stats_, partial_report);
Henrik Boström40b030e2019-02-28 09:49:31 +01001426 ProduceTransportStats_n(timestamp_us, transport_stats_by_name,
1427 transport_cert_stats, partial_report);
Henrik Boström883eefc2019-05-27 13:40:25 +02001428 ProduceRTPStreamStats_n(timestamp_us, transceiver_stats_infos_,
1429 partial_report);
Henrik Boström40b030e2019-02-28 09:49:31 +01001430}
1431
1432void RTCStatsCollector::MergeNetworkReport_s() {
Tomas Gunnarsson67b1fa22021-04-08 15:18:05 +02001433 RTC_DCHECK_RUN_ON(signaling_thread_);
Artem Titov880fa812021-07-30 22:30:23 +02001434 // The `network_report_event_` must be signaled for it to be safe to touch
1435 // `network_report_`. This is normally not blocking, but if
Henrik Boström40b030e2019-02-28 09:49:31 +01001436 // WaitForPendingRequest() is called while a request is pending, we might have
Artem Titov880fa812021-07-30 22:30:23 +02001437 // to wait until the network thread is done touching `network_report_`.
Henrik Boström40b030e2019-02-28 09:49:31 +01001438 network_report_event_.Wait(rtc::Event::kForever);
1439 if (!network_report_) {
1440 // Normally, MergeNetworkReport_s() is executed because it is posted from
1441 // the network thread. But if WaitForPendingRequest() is called while a
1442 // request is pending, an early call to MergeNetworkReport_s() is made,
Artem Titov880fa812021-07-30 22:30:23 +02001443 // merging the report and setting `network_report_` to null. If so, when the
Henrik Boström40b030e2019-02-28 09:49:31 +01001444 // previously posted MergeNetworkReport_s() is later executed, the report is
1445 // already null and nothing needs to be done here.
hbosc82f2e12016-09-05 01:36:50 -07001446 return;
1447 }
Mirko Bonadeica890ee2019-02-15 21:10:40 +00001448 RTC_DCHECK_GT(num_pending_partial_reports_, 0);
Henrik Boström40b030e2019-02-28 09:49:31 +01001449 RTC_DCHECK(partial_report_);
1450 partial_report_->TakeMembersFrom(network_report_);
1451 network_report_ = nullptr;
Mirko Bonadeica890ee2019-02-15 21:10:40 +00001452 --num_pending_partial_reports_;
Artem Titov880fa812021-07-30 22:30:23 +02001453 // `network_report_` is currently the only partial report collected
1454 // asynchronously, so `num_pending_partial_reports_` must now be 0 and we are
Henrik Boström40b030e2019-02-28 09:49:31 +01001455 // ready to deliver the result.
1456 RTC_DCHECK_EQ(num_pending_partial_reports_, 0);
1457 cache_timestamp_us_ = partial_report_timestamp_us_;
1458 cached_report_ = partial_report_;
1459 partial_report_ = nullptr;
1460 transceiver_stats_infos_.clear();
1461 // Trace WebRTC Stats when getStats is called on Javascript.
1462 // This allows access to WebRTC stats from trace logs. To enable them,
1463 // select the "webrtc_stats" category when recording traces.
1464 TRACE_EVENT_INSTANT1("webrtc_stats", "webrtc_stats", "report",
1465 cached_report_->ToJson());
Mirko Bonadeica890ee2019-02-15 21:10:40 +00001466
Artem Titov880fa812021-07-30 22:30:23 +02001467 // Deliver report and clear `requests_`.
Henrik Boström40b030e2019-02-28 09:49:31 +01001468 std::vector<RequestInfo> requests;
1469 requests.swap(requests_);
1470 DeliverCachedReport(cached_report_, std::move(requests));
hbosc82f2e12016-09-05 01:36:50 -07001471}
1472
Taylor Brandstetter25e022f2018-03-08 09:53:47 -08001473void RTCStatsCollector::DeliverCachedReport(
1474 rtc::scoped_refptr<const RTCStatsReport> cached_report,
Henrik Boström5b3541f2018-03-19 13:52:56 +01001475 std::vector<RTCStatsCollector::RequestInfo> requests) {
Tomas Gunnarsson67b1fa22021-04-08 15:18:05 +02001476 RTC_DCHECK_RUN_ON(signaling_thread_);
Henrik Boström5b3541f2018-03-19 13:52:56 +01001477 RTC_DCHECK(!requests.empty());
Taylor Brandstetter25e022f2018-03-08 09:53:47 -08001478 RTC_DCHECK(cached_report);
Taylor Brandstetter87d5a742018-03-06 09:42:25 -08001479
Henrik Boström5b3541f2018-03-19 13:52:56 +01001480 for (const RequestInfo& request : requests) {
1481 if (request.filter_mode() == RequestInfo::FilterMode::kAll) {
1482 request.callback()->OnStatsDelivered(cached_report);
1483 } else {
1484 bool filter_by_sender_selector;
1485 rtc::scoped_refptr<RtpSenderInternal> sender_selector;
1486 rtc::scoped_refptr<RtpReceiverInternal> receiver_selector;
1487 if (request.filter_mode() == RequestInfo::FilterMode::kSenderSelector) {
1488 filter_by_sender_selector = true;
1489 sender_selector = request.sender_selector();
1490 } else {
1491 RTC_DCHECK(request.filter_mode() ==
1492 RequestInfo::FilterMode::kReceiverSelector);
1493 filter_by_sender_selector = false;
1494 receiver_selector = request.receiver_selector();
1495 }
1496 request.callback()->OnStatsDelivered(CreateReportFilteredBySelector(
1497 filter_by_sender_selector, cached_report, sender_selector,
1498 receiver_selector));
1499 }
hbosc82f2e12016-09-05 01:36:50 -07001500 }
hbosd565b732016-08-30 14:04:35 -07001501}
1502
hbosdf6075a2016-12-19 04:58:02 -08001503void RTCStatsCollector::ProduceCertificateStats_n(
hbos2fa7c672016-10-24 04:00:05 -07001504 int64_t timestamp_us,
1505 const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
hbos6ab97ce2016-10-03 14:16:56 -07001506 RTCStatsReport* report) const {
Tomas Gunnarsson67b1fa22021-04-08 15:18:05 +02001507 RTC_DCHECK_RUN_ON(network_thread_);
Henrik Boströme88c95e2020-07-08 11:18:50 +02001508 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1509
hbos02ba2112016-10-28 05:14:53 -07001510 for (const auto& transport_cert_stats_pair : transport_cert_stats) {
1511 if (transport_cert_stats_pair.second.local) {
1512 ProduceCertificateStatsFromSSLCertificateStats(
1513 timestamp_us, *transport_cert_stats_pair.second.local.get(), report);
hbos6ab97ce2016-10-03 14:16:56 -07001514 }
hbos02ba2112016-10-28 05:14:53 -07001515 if (transport_cert_stats_pair.second.remote) {
1516 ProduceCertificateStatsFromSSLCertificateStats(
1517 timestamp_us, *transport_cert_stats_pair.second.remote.get(), report);
hbos6ab97ce2016-10-03 14:16:56 -07001518 }
1519 }
1520}
1521
hbosdf6075a2016-12-19 04:58:02 -08001522void RTCStatsCollector::ProduceCodecStats_n(
Steve Anton57858b32018-02-15 15:19:50 -08001523 int64_t timestamp_us,
1524 const std::vector<RtpTransceiverStatsInfo>& transceiver_stats_infos,
hbos0adb8282016-11-23 02:32:06 -08001525 RTCStatsReport* report) const {
Tomas Gunnarsson67b1fa22021-04-08 15:18:05 +02001526 RTC_DCHECK_RUN_ON(network_thread_);
Henrik Boströme88c95e2020-07-08 11:18:50 +02001527 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1528
Steve Anton57858b32018-02-15 15:19:50 -08001529 for (const auto& stats : transceiver_stats_infos) {
1530 if (!stats.mid) {
1531 continue;
hbos0adb8282016-11-23 02:32:06 -08001532 }
Philipp Hancke95157a02020-11-16 20:08:27 +01001533 std::string transport_id = RTCTransportStatsIDFromTransportChannel(
1534 *stats.transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
1535
Steve Anton57858b32018-02-15 15:19:50 -08001536 const cricket::VoiceMediaInfo* voice_media_info =
1537 stats.track_media_info_map->voice_media_info();
1538 const cricket::VideoMediaInfo* video_media_info =
1539 stats.track_media_info_map->video_media_info();
1540 // Audio
1541 if (voice_media_info) {
1542 // Inbound
1543 for (const auto& pair : voice_media_info->receive_codecs) {
1544 report->AddStats(CodecStatsFromRtpCodecParameters(
Philipp Hancke95157a02020-11-16 20:08:27 +01001545 timestamp_us, *stats.mid, transport_id, true, pair.second));
Steve Anton57858b32018-02-15 15:19:50 -08001546 }
1547 // Outbound
1548 for (const auto& pair : voice_media_info->send_codecs) {
1549 report->AddStats(CodecStatsFromRtpCodecParameters(
Philipp Hancke95157a02020-11-16 20:08:27 +01001550 timestamp_us, *stats.mid, transport_id, false, pair.second));
Steve Anton57858b32018-02-15 15:19:50 -08001551 }
Guido Urdanetaee2388f2018-02-15 16:36:19 +00001552 }
Steve Anton57858b32018-02-15 15:19:50 -08001553 // Video
1554 if (video_media_info) {
1555 // Inbound
1556 for (const auto& pair : video_media_info->receive_codecs) {
1557 report->AddStats(CodecStatsFromRtpCodecParameters(
Philipp Hancke95157a02020-11-16 20:08:27 +01001558 timestamp_us, *stats.mid, transport_id, true, pair.second));
Steve Anton57858b32018-02-15 15:19:50 -08001559 }
1560 // Outbound
1561 for (const auto& pair : video_media_info->send_codecs) {
1562 report->AddStats(CodecStatsFromRtpCodecParameters(
Philipp Hancke95157a02020-11-16 20:08:27 +01001563 timestamp_us, *stats.mid, transport_id, false, pair.second));
Steve Anton57858b32018-02-15 15:19:50 -08001564 }
hbos0adb8282016-11-23 02:32:06 -08001565 }
1566 }
1567}
1568
hboscc555c52016-10-18 12:48:31 -07001569void RTCStatsCollector::ProduceDataChannelStats_s(
Jonas Olssona4d87372019-07-05 19:08:33 +02001570 int64_t timestamp_us,
1571 RTCStatsReport* report) const {
Tomas Gunnarsson2e94de52020-06-16 16:54:10 +02001572 RTC_DCHECK_RUN_ON(signaling_thread_);
Henrik Boströme88c95e2020-07-08 11:18:50 +02001573 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
Taylor Brandstetter3a034e12020-07-09 15:32:34 -07001574 std::vector<DataChannelStats> data_stats = pc_->GetDataChannelStats();
Tomas Gunnarsson2e94de52020-06-16 16:54:10 +02001575 for (const auto& stats : data_stats) {
hboscc555c52016-10-18 12:48:31 -07001576 std::unique_ptr<RTCDataChannelStats> data_channel_stats(
1577 new RTCDataChannelStats(
Tomas Gunnarsson2e94de52020-06-16 16:54:10 +02001578 "RTCDataChannel_" + rtc::ToString(stats.internal_id),
hboscc555c52016-10-18 12:48:31 -07001579 timestamp_us));
Tomas Gunnarsson2e94de52020-06-16 16:54:10 +02001580 data_channel_stats->label = std::move(stats.label);
1581 data_channel_stats->protocol = std::move(stats.protocol);
1582 data_channel_stats->data_channel_identifier = stats.id;
1583 data_channel_stats->state = DataStateToRTCDataChannelState(stats.state);
1584 data_channel_stats->messages_sent = stats.messages_sent;
1585 data_channel_stats->bytes_sent = stats.bytes_sent;
1586 data_channel_stats->messages_received = stats.messages_received;
1587 data_channel_stats->bytes_received = stats.bytes_received;
hboscc555c52016-10-18 12:48:31 -07001588 report->AddStats(std::move(data_channel_stats));
1589 }
1590}
1591
hbosdf6075a2016-12-19 04:58:02 -08001592void RTCStatsCollector::ProduceIceCandidateAndPairStats_n(
stefanf79ade12017-06-02 06:44:03 -07001593 int64_t timestamp_us,
Steve Anton5dfde182018-02-06 10:34:40 -08001594 const std::map<std::string, cricket::TransportStats>&
1595 transport_stats_by_name,
stefanf79ade12017-06-02 06:44:03 -07001596 const Call::Stats& call_stats,
1597 RTCStatsReport* report) const {
Tomas Gunnarsson67b1fa22021-04-08 15:18:05 +02001598 RTC_DCHECK_RUN_ON(network_thread_);
Henrik Boströme88c95e2020-07-08 11:18:50 +02001599 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1600
Steve Anton5dfde182018-02-06 10:34:40 -08001601 for (const auto& entry : transport_stats_by_name) {
1602 const std::string& transport_name = entry.first;
1603 const cricket::TransportStats& transport_stats = entry.second;
1604 for (const auto& channel_stats : transport_stats.channel_stats) {
hbos0583b282016-11-30 01:50:14 -08001605 std::string transport_id = RTCTransportStatsIDFromTransportChannel(
Steve Anton5dfde182018-02-06 10:34:40 -08001606 transport_name, channel_stats.component);
hbosc47a0c32016-10-11 14:54:49 -07001607 for (const cricket::ConnectionInfo& info :
Jonas Oreland149dc722019-08-28 08:10:27 +02001608 channel_stats.ice_transport_stats.connection_infos) {
hbosc47a0c32016-10-11 14:54:49 -07001609 std::unique_ptr<RTCIceCandidatePairStats> candidate_pair_stats(
hbos2fa7c672016-10-24 04:00:05 -07001610 new RTCIceCandidatePairStats(
1611 RTCIceCandidatePairStatsIDFromConnectionInfo(info),
1612 timestamp_us));
hbosc47a0c32016-10-11 14:54:49 -07001613
hbos0583b282016-11-30 01:50:14 -08001614 candidate_pair_stats->transport_id = transport_id;
hbosab9f6e42016-10-07 02:18:47 -07001615 // TODO(hbos): There could be other candidates that are not paired with
1616 // anything. We don't have a complete list. Local candidates come from
1617 // Port objects, and prflx candidates (both local and remote) are only
Harald Alvestrand89061872018-01-02 14:08:34 +01001618 // stored in candidate pairs. https://crbug.com/632723
hbos02ba2112016-10-28 05:14:53 -07001619 candidate_pair_stats->local_candidate_id = ProduceIceCandidateStats(
hbosb4e426e2017-01-02 09:59:31 -08001620 timestamp_us, info.local_candidate, true, transport_id, report);
hbos02ba2112016-10-28 05:14:53 -07001621 candidate_pair_stats->remote_candidate_id = ProduceIceCandidateStats(
hbosb4e426e2017-01-02 09:59:31 -08001622 timestamp_us, info.remote_candidate, false, transport_id, report);
hbos06495bc2017-01-02 08:08:18 -08001623 candidate_pair_stats->state =
1624 IceCandidatePairStateToRTCStatsIceCandidatePairState(info.state);
1625 candidate_pair_stats->priority = info.priority;
hbos92eaec62017-02-27 01:38:08 -08001626 candidate_pair_stats->nominated = info.nominated;
hbosc47a0c32016-10-11 14:54:49 -07001627 // TODO(hbos): This writable is different than the spec. It goes to
1628 // false after a certain amount of time without a response passes.
Harald Alvestrand89061872018-01-02 14:08:34 +01001629 // https://crbug.com/633550
hbosc47a0c32016-10-11 14:54:49 -07001630 candidate_pair_stats->writable = info.writable;
Taylor Brandstetter79326ea2021-09-28 15:09:53 -07001631 // Note that sent_total_packets includes discarded packets but
1632 // sent_total_bytes does not.
1633 candidate_pair_stats->packets_sent = static_cast<uint64_t>(
1634 info.sent_total_packets - info.sent_discarded_packets);
1635 candidate_pair_stats->packets_discarded_on_send =
1636 static_cast<uint64_t>(info.sent_discarded_packets);
1637 candidate_pair_stats->packets_received =
1638 static_cast<uint64_t>(info.packets_received);
hbosc47a0c32016-10-11 14:54:49 -07001639 candidate_pair_stats->bytes_sent =
1640 static_cast<uint64_t>(info.sent_total_bytes);
Taylor Brandstetter79326ea2021-09-28 15:09:53 -07001641 candidate_pair_stats->bytes_discarded_on_send =
1642 static_cast<uint64_t>(info.sent_discarded_bytes);
hbosc47a0c32016-10-11 14:54:49 -07001643 candidate_pair_stats->bytes_received =
1644 static_cast<uint64_t>(info.recv_total_bytes);
hbosbf8d3e52017-02-28 06:34:47 -08001645 candidate_pair_stats->total_round_trip_time =
1646 static_cast<double>(info.total_round_trip_time_ms) /
1647 rtc::kNumMillisecsPerSec;
1648 if (info.current_round_trip_time_ms) {
1649 candidate_pair_stats->current_round_trip_time =
1650 static_cast<double>(*info.current_round_trip_time_ms) /
1651 rtc::kNumMillisecsPerSec;
1652 }
stefanf79ade12017-06-02 06:44:03 -07001653 if (info.best_connection) {
hbos338f78a2017-02-07 06:41:21 -08001654 // The bandwidth estimations we have are for the selected candidate
1655 // pair ("info.best_connection").
stefanf79ade12017-06-02 06:44:03 -07001656 RTC_DCHECK_GE(call_stats.send_bandwidth_bps, 0);
1657 RTC_DCHECK_GE(call_stats.recv_bandwidth_bps, 0);
1658 if (call_stats.send_bandwidth_bps > 0) {
hbos338f78a2017-02-07 06:41:21 -08001659 candidate_pair_stats->available_outgoing_bitrate =
stefanf79ade12017-06-02 06:44:03 -07001660 static_cast<double>(call_stats.send_bandwidth_bps);
hbos338f78a2017-02-07 06:41:21 -08001661 }
stefanf79ade12017-06-02 06:44:03 -07001662 if (call_stats.recv_bandwidth_bps > 0) {
hbos338f78a2017-02-07 06:41:21 -08001663 candidate_pair_stats->available_incoming_bitrate =
stefanf79ade12017-06-02 06:44:03 -07001664 static_cast<double>(call_stats.recv_bandwidth_bps);
hbos338f78a2017-02-07 06:41:21 -08001665 }
1666 }
hbosd82f5122016-12-09 04:12:39 -08001667 candidate_pair_stats->requests_received =
1668 static_cast<uint64_t>(info.recv_ping_requests);
hbose448dd52016-12-12 01:22:53 -08001669 candidate_pair_stats->requests_sent = static_cast<uint64_t>(
1670 info.sent_ping_requests_before_first_response);
hbosc47a0c32016-10-11 14:54:49 -07001671 candidate_pair_stats->responses_received =
1672 static_cast<uint64_t>(info.recv_ping_responses);
1673 candidate_pair_stats->responses_sent =
1674 static_cast<uint64_t>(info.sent_ping_responses);
hbose448dd52016-12-12 01:22:53 -08001675 RTC_DCHECK_GE(info.sent_ping_requests_total,
1676 info.sent_ping_requests_before_first_response);
1677 candidate_pair_stats->consent_requests_sent = static_cast<uint64_t>(
1678 info.sent_ping_requests_total -
1679 info.sent_ping_requests_before_first_response);
hbosc47a0c32016-10-11 14:54:49 -07001680
1681 report->AddStats(std::move(candidate_pair_stats));
hbosab9f6e42016-10-07 02:18:47 -07001682 }
1683 }
1684 }
1685}
1686
Steve Anton57858b32018-02-15 15:19:50 -08001687void RTCStatsCollector::ProduceMediaStreamStats_s(
1688 int64_t timestamp_us,
1689 RTCStatsReport* report) const {
Tomas Gunnarsson67b1fa22021-04-08 15:18:05 +02001690 RTC_DCHECK_RUN_ON(signaling_thread_);
Henrik Boströme88c95e2020-07-08 11:18:50 +02001691 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
Steve Anton57858b32018-02-15 15:19:50 -08001692
1693 std::map<std::string, std::vector<std::string>> track_ids;
1694
1695 for (const auto& stats : transceiver_stats_infos_) {
Mirko Bonadei739baf02019-01-27 17:29:42 +01001696 for (const auto& sender : stats.transceiver->senders()) {
Steve Anton57858b32018-02-15 15:19:50 -08001697 std::string track_id =
1698 RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
1699 kSender, sender->internal()->AttachmentId());
1700 for (auto& stream_id : sender->stream_ids()) {
1701 track_ids[stream_id].push_back(track_id);
1702 }
1703 }
Mirko Bonadei739baf02019-01-27 17:29:42 +01001704 for (const auto& receiver : stats.transceiver->receivers()) {
Steve Anton57858b32018-02-15 15:19:50 -08001705 std::string track_id =
1706 RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
1707 kReceiver, receiver->internal()->AttachmentId());
1708 for (auto& stream : receiver->streams()) {
Seth Hampson13b8bad2018-03-13 16:05:28 -07001709 track_ids[stream->id()].push_back(track_id);
Steve Anton57858b32018-02-15 15:19:50 -08001710 }
1711 }
1712 }
1713
1714 // Build stats for each stream ID known.
1715 for (auto& it : track_ids) {
1716 std::unique_ptr<RTCMediaStreamStats> stream_stats(
1717 new RTCMediaStreamStats("RTCMediaStream_" + it.first, timestamp_us));
1718 stream_stats->stream_identifier = it.first;
1719 stream_stats->track_ids = it.second;
1720 report->AddStats(std::move(stream_stats));
1721 }
1722}
1723
1724void RTCStatsCollector::ProduceMediaStreamTrackStats_s(
1725 int64_t timestamp_us,
1726 RTCStatsReport* report) const {
Tomas Gunnarsson67b1fa22021-04-08 15:18:05 +02001727 RTC_DCHECK_RUN_ON(signaling_thread_);
Henrik Boströme88c95e2020-07-08 11:18:50 +02001728 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1729
Steve Anton57858b32018-02-15 15:19:50 -08001730 for (const RtpTransceiverStatsInfo& stats : transceiver_stats_infos_) {
1731 std::vector<rtc::scoped_refptr<RtpSenderInternal>> senders;
Mirko Bonadei739baf02019-01-27 17:29:42 +01001732 for (const auto& sender : stats.transceiver->senders()) {
Niels Möllere7cc8832022-01-04 15:20:03 +01001733 senders.push_back(
1734 rtc::scoped_refptr<RtpSenderInternal>(sender->internal()));
Steve Anton57858b32018-02-15 15:19:50 -08001735 }
1736 ProduceSenderMediaTrackStats(timestamp_us, *stats.track_media_info_map,
1737 senders, report);
1738
1739 std::vector<rtc::scoped_refptr<RtpReceiverInternal>> receivers;
Mirko Bonadei739baf02019-01-27 17:29:42 +01001740 for (const auto& receiver : stats.transceiver->receivers()) {
Niels Möllere7cc8832022-01-04 15:20:03 +01001741 receivers.push_back(
1742 rtc::scoped_refptr<RtpReceiverInternal>(receiver->internal()));
Steve Anton57858b32018-02-15 15:19:50 -08001743 }
1744 ProduceReceiverMediaTrackStats(timestamp_us, *stats.track_media_info_map,
1745 receivers, report);
1746 }
hbos09bc1282016-11-08 06:29:22 -08001747}
1748
Henrik Boström646fda02019-05-22 15:49:42 +02001749void RTCStatsCollector::ProduceMediaSourceStats_s(
1750 int64_t timestamp_us,
1751 RTCStatsReport* report) const {
Tomas Gunnarsson67b1fa22021-04-08 15:18:05 +02001752 RTC_DCHECK_RUN_ON(signaling_thread_);
Henrik Boströme88c95e2020-07-08 11:18:50 +02001753 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1754
Henrik Boström646fda02019-05-22 15:49:42 +02001755 for (const RtpTransceiverStatsInfo& transceiver_stats_info :
1756 transceiver_stats_infos_) {
1757 const auto& track_media_info_map =
1758 transceiver_stats_info.track_media_info_map;
1759 for (const auto& sender : transceiver_stats_info.transceiver->senders()) {
1760 const auto& sender_internal = sender->internal();
1761 const auto& track = sender_internal->track();
1762 if (!track)
1763 continue;
Henrik Boströmd2c336f2019-07-03 17:11:10 +02001764 // TODO(https://crbug.com/webrtc/10771): The same track could be attached
1765 // to multiple senders which should result in multiple senders referencing
1766 // the same media-source stats. When all media source related metrics are
1767 // moved to the track's source (e.g. input frame rate is moved from
1768 // cricket::VideoSenderInfo to VideoTrackSourceInterface::Stats and audio
1769 // levels are moved to the corresponding audio track/source object), don't
1770 // create separate media source stats objects on a per-attachment basis.
Henrik Boström646fda02019-05-22 15:49:42 +02001771 std::unique_ptr<RTCMediaSourceStats> media_source_stats;
1772 if (track->kind() == MediaStreamTrackInterface::kAudioKind) {
Taylor Brandstetter64851c02021-06-24 13:32:50 -07001773 AudioTrackInterface* audio_track =
1774 static_cast<AudioTrackInterface*>(track.get());
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001775 auto audio_source_stats = std::make_unique<RTCAudioSourceStats>(
Henrik Boström646fda02019-05-22 15:49:42 +02001776 RTCMediaSourceStatsIDFromKindAndAttachment(
1777 cricket::MEDIA_TYPE_AUDIO, sender_internal->AttachmentId()),
1778 timestamp_us);
Henrik Boströmd2c336f2019-07-03 17:11:10 +02001779 // TODO(https://crbug.com/webrtc/10771): We shouldn't need to have an
1780 // SSRC assigned (there shouldn't need to exist a send-stream, created
1781 // by an O/A exchange) in order to read audio media-source stats.
1782 // TODO(https://crbug.com/webrtc/8694): SSRC 0 shouldn't be a magic
1783 // value indicating no SSRC.
1784 if (sender_internal->ssrc() != 0) {
1785 auto* voice_sender_info =
1786 track_media_info_map->GetVoiceSenderInfoBySsrc(
1787 sender_internal->ssrc());
1788 if (voice_sender_info) {
1789 audio_source_stats->audio_level = DoubleAudioLevelFromIntAudioLevel(
1790 voice_sender_info->audio_level);
1791 audio_source_stats->total_audio_energy =
1792 voice_sender_info->total_input_energy;
1793 audio_source_stats->total_samples_duration =
1794 voice_sender_info->total_input_duration;
Taylor Brandstetter64851c02021-06-24 13:32:50 -07001795 SetAudioProcessingStats(audio_source_stats.get(),
1796 voice_sender_info->apm_statistics);
Henrik Boströmd2c336f2019-07-03 17:11:10 +02001797 }
1798 }
Taylor Brandstetter64851c02021-06-24 13:32:50 -07001799 // Audio processor may be attached to either the track or the send
1800 // stream, so look in both places.
1801 auto audio_processor(audio_track->GetAudioProcessor());
1802 if (audio_processor.get()) {
Artem Titov880fa812021-07-30 22:30:23 +02001803 // The `has_remote_tracks` argument is obsolete; makes no difference
Taylor Brandstetter64851c02021-06-24 13:32:50 -07001804 // if it's set to true or false.
1805 AudioProcessorInterface::AudioProcessorStatistics ap_stats =
1806 audio_processor->GetStats(/*has_remote_tracks=*/false);
1807 SetAudioProcessingStats(audio_source_stats.get(),
1808 ap_stats.apm_statistics);
1809 }
Henrik Boströmd2c336f2019-07-03 17:11:10 +02001810 media_source_stats = std::move(audio_source_stats);
Henrik Boström646fda02019-05-22 15:49:42 +02001811 } else {
1812 RTC_DCHECK_EQ(MediaStreamTrackInterface::kVideoKind, track->kind());
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001813 auto video_source_stats = std::make_unique<RTCVideoSourceStats>(
Henrik Boström646fda02019-05-22 15:49:42 +02001814 RTCMediaSourceStatsIDFromKindAndAttachment(
1815 cricket::MEDIA_TYPE_VIDEO, sender_internal->AttachmentId()),
1816 timestamp_us);
1817 auto* video_track = static_cast<VideoTrackInterface*>(track.get());
1818 auto* video_source = video_track->GetSource();
1819 VideoTrackSourceInterface::Stats source_stats;
1820 if (video_source && video_source->GetStats(&source_stats)) {
1821 video_source_stats->width = source_stats.input_width;
1822 video_source_stats->height = source_stats.input_height;
1823 }
Henrik Boströmd2c336f2019-07-03 17:11:10 +02001824 // TODO(https://crbug.com/webrtc/10771): We shouldn't need to have an
1825 // SSRC assigned (there shouldn't need to exist a send-stream, created
1826 // by an O/A exchange) in order to get framesPerSecond.
1827 // TODO(https://crbug.com/webrtc/8694): SSRC 0 shouldn't be a magic
1828 // value indicating no SSRC.
Henrik Boström646fda02019-05-22 15:49:42 +02001829 if (sender_internal->ssrc() != 0) {
Henrik Boströmd2c336f2019-07-03 17:11:10 +02001830 auto* video_sender_info =
1831 track_media_info_map->GetVideoSenderInfoBySsrc(
1832 sender_internal->ssrc());
1833 if (video_sender_info) {
Henrik Boström646fda02019-05-22 15:49:42 +02001834 video_source_stats->frames_per_second =
Henrik Boströmd2c336f2019-07-03 17:11:10 +02001835 video_sender_info->framerate_input;
Di Wu668dbf62021-02-27 00:29:15 -08001836 video_source_stats->frames = video_sender_info->frames;
Henrik Boström646fda02019-05-22 15:49:42 +02001837 }
1838 }
1839 media_source_stats = std::move(video_source_stats);
1840 }
1841 media_source_stats->track_identifier = track->id();
1842 media_source_stats->kind = track->kind();
1843 report->AddStats(std::move(media_source_stats));
1844 }
1845 }
1846}
1847
hbos6ab97ce2016-10-03 14:16:56 -07001848void RTCStatsCollector::ProducePeerConnectionStats_s(
Jonas Olssona4d87372019-07-05 19:08:33 +02001849 int64_t timestamp_us,
1850 RTCStatsReport* report) const {
Tomas Gunnarsson67b1fa22021-04-08 15:18:05 +02001851 RTC_DCHECK_RUN_ON(signaling_thread_);
Henrik Boströme88c95e2020-07-08 11:18:50 +02001852 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1853
hbosd565b732016-08-30 14:04:35 -07001854 std::unique_ptr<RTCPeerConnectionStats> stats(
Jonas Olssona4d87372019-07-05 19:08:33 +02001855 new RTCPeerConnectionStats("RTCPeerConnection", timestamp_us));
hbos82ebe022016-11-14 01:41:09 -08001856 stats->data_channels_opened = internal_record_.data_channels_opened;
1857 stats->data_channels_closed = internal_record_.data_channels_closed;
hbos6ab97ce2016-10-03 14:16:56 -07001858 report->AddStats(std::move(stats));
hbosd565b732016-08-30 14:04:35 -07001859}
1860
hbosdf6075a2016-12-19 04:58:02 -08001861void RTCStatsCollector::ProduceRTPStreamStats_n(
Steve Anton593e3252017-12-15 11:44:48 -08001862 int64_t timestamp_us,
Steve Anton57858b32018-02-15 15:19:50 -08001863 const std::vector<RtpTransceiverStatsInfo>& transceiver_stats_infos,
hbos84abeb12017-01-16 06:16:44 -08001864 RTCStatsReport* report) const {
Tomas Gunnarsson67b1fa22021-04-08 15:18:05 +02001865 RTC_DCHECK_RUN_ON(network_thread_);
Henrik Boströme88c95e2020-07-08 11:18:50 +02001866 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
hbos6ded1902016-11-01 01:50:46 -07001867
Steve Anton57858b32018-02-15 15:19:50 -08001868 for (const RtpTransceiverStatsInfo& stats : transceiver_stats_infos) {
1869 if (stats.media_type == cricket::MEDIA_TYPE_AUDIO) {
1870 ProduceAudioRTPStreamStats_n(timestamp_us, stats, report);
1871 } else if (stats.media_type == cricket::MEDIA_TYPE_VIDEO) {
1872 ProduceVideoRTPStreamStats_n(timestamp_us, stats, report);
1873 } else {
Artem Titovd3251962021-11-15 16:57:07 +01001874 RTC_DCHECK_NOTREACHED();
Guido Urdanetaee2388f2018-02-15 16:36:19 +00001875 }
Steve Anton56bae8d2018-02-14 16:07:42 -08001876 }
Steve Anton57858b32018-02-15 15:19:50 -08001877}
1878
1879void RTCStatsCollector::ProduceAudioRTPStreamStats_n(
1880 int64_t timestamp_us,
1881 const RtpTransceiverStatsInfo& stats,
1882 RTCStatsReport* report) const {
Tomas Gunnarsson67b1fa22021-04-08 15:18:05 +02001883 RTC_DCHECK_RUN_ON(network_thread_);
Henrik Boströme88c95e2020-07-08 11:18:50 +02001884 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1885
Steve Anton57858b32018-02-15 15:19:50 -08001886 if (!stats.mid || !stats.transport_name) {
1887 return;
1888 }
1889 RTC_DCHECK(stats.track_media_info_map);
1890 const TrackMediaInfoMap& track_media_info_map = *stats.track_media_info_map;
1891 RTC_DCHECK(track_media_info_map.voice_media_info());
1892 std::string mid = *stats.mid;
1893 std::string transport_id = RTCTransportStatsIDFromTransportChannel(
1894 *stats.transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +01001895 // Inbound and remote-outbound.
1896 // The remote-outbound stats are based on RTCP sender reports sent from the
1897 // remote endpoint providing metrics about the remote outbound streams.
Steve Anton57858b32018-02-15 15:19:50 -08001898 for (const cricket::VoiceReceiverInfo& voice_receiver_info :
1899 track_media_info_map.voice_media_info()->receivers) {
1900 if (!voice_receiver_info.connected())
1901 continue;
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +01001902 // Inbound.
1903 auto inbound_audio =
1904 CreateInboundAudioStreamStats(voice_receiver_info, mid, timestamp_us);
Steve Anton57858b32018-02-15 15:19:50 -08001905 // TODO(hta): This lookup should look for the sender, not the track.
1906 rtc::scoped_refptr<AudioTrackInterface> audio_track =
1907 track_media_info_map.GetAudioTrack(voice_receiver_info);
1908 if (audio_track) {
1909 inbound_audio->track_id =
1910 RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
1911 kReceiver,
Niels Möllerafb246b2022-04-20 14:26:50 +02001912 track_media_info_map.GetAttachmentIdByTrack(audio_track.get())
1913 .value());
hbos6ded1902016-11-01 01:50:46 -07001914 }
Steve Anton57858b32018-02-15 15:19:50 -08001915 inbound_audio->transport_id = transport_id;
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +01001916 // Remote-outbound.
1917 auto remote_outbound_audio = CreateRemoteOutboundAudioStreamStats(
1918 voice_receiver_info, mid, inbound_audio->id(), transport_id);
1919 // Add stats.
1920 if (remote_outbound_audio) {
1921 // When the remote outbound stats are available, the remote ID for the
1922 // local inbound stats is set.
1923 inbound_audio->remote_id = remote_outbound_audio->id();
1924 report->AddStats(std::move(remote_outbound_audio));
1925 }
Steve Anton57858b32018-02-15 15:19:50 -08001926 report->AddStats(std::move(inbound_audio));
1927 }
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +01001928 // Outbound.
Henrik Boström4f40fa52019-12-19 13:27:27 +01001929 std::map<std::string, RTCOutboundRTPStreamStats*> audio_outbound_rtps;
Steve Anton57858b32018-02-15 15:19:50 -08001930 for (const cricket::VoiceSenderInfo& voice_sender_info :
1931 track_media_info_map.voice_media_info()->senders) {
1932 if (!voice_sender_info.connected())
1933 continue;
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001934 auto outbound_audio = std::make_unique<RTCOutboundRTPStreamStats>(
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +01001935 RTCOutboundRTPStreamStatsIDFromSSRC(cricket::MEDIA_TYPE_AUDIO,
1936 voice_sender_info.ssrc()),
Steve Anton57858b32018-02-15 15:19:50 -08001937 timestamp_us);
1938 SetOutboundRTPStreamStatsFromVoiceSenderInfo(mid, voice_sender_info,
1939 outbound_audio.get());
1940 rtc::scoped_refptr<AudioTrackInterface> audio_track =
1941 track_media_info_map.GetAudioTrack(voice_sender_info);
1942 if (audio_track) {
Henrik Boström646fda02019-05-22 15:49:42 +02001943 int attachment_id =
Niels Möllerafb246b2022-04-20 14:26:50 +02001944 track_media_info_map.GetAttachmentIdByTrack(audio_track.get())
1945 .value();
Steve Anton57858b32018-02-15 15:19:50 -08001946 outbound_audio->track_id =
Henrik Boström646fda02019-05-22 15:49:42 +02001947 RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(kSender,
1948 attachment_id);
1949 outbound_audio->media_source_id =
1950 RTCMediaSourceStatsIDFromKindAndAttachment(cricket::MEDIA_TYPE_AUDIO,
1951 attachment_id);
Steve Anton56bae8d2018-02-14 16:07:42 -08001952 }
Steve Anton57858b32018-02-15 15:19:50 -08001953 outbound_audio->transport_id = transport_id;
Henrik Boström4f40fa52019-12-19 13:27:27 +01001954 audio_outbound_rtps.insert(
1955 std::make_pair(outbound_audio->id(), outbound_audio.get()));
Steve Anton57858b32018-02-15 15:19:50 -08001956 report->AddStats(std::move(outbound_audio));
1957 }
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +01001958 // Remote-inbound.
Henrik Boström883eefc2019-05-27 13:40:25 +02001959 // These are Report Block-based, information sent from the remote endpoint,
1960 // providing metrics about our Outbound streams. We take advantage of the fact
1961 // that RTCOutboundRtpStreamStats, RTCCodecStats and RTCTransport have already
1962 // been added to the report.
1963 for (const cricket::VoiceSenderInfo& voice_sender_info :
1964 track_media_info_map.voice_media_info()->senders) {
1965 for (const auto& report_block_data : voice_sender_info.report_block_datas) {
1966 report->AddStats(ProduceRemoteInboundRtpStreamStatsFromReportBlockData(
Eldar Relloc07e9042020-07-03 11:08:07 +03001967 report_block_data, cricket::MEDIA_TYPE_AUDIO, audio_outbound_rtps,
1968 *report));
Henrik Boström883eefc2019-05-27 13:40:25 +02001969 }
1970 }
Steve Anton57858b32018-02-15 15:19:50 -08001971}
1972
1973void RTCStatsCollector::ProduceVideoRTPStreamStats_n(
1974 int64_t timestamp_us,
1975 const RtpTransceiverStatsInfo& stats,
1976 RTCStatsReport* report) const {
Tomas Gunnarsson67b1fa22021-04-08 15:18:05 +02001977 RTC_DCHECK_RUN_ON(network_thread_);
Henrik Boströme88c95e2020-07-08 11:18:50 +02001978 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1979
Steve Anton57858b32018-02-15 15:19:50 -08001980 if (!stats.mid || !stats.transport_name) {
1981 return;
1982 }
1983 RTC_DCHECK(stats.track_media_info_map);
1984 const TrackMediaInfoMap& track_media_info_map = *stats.track_media_info_map;
1985 RTC_DCHECK(track_media_info_map.video_media_info());
1986 std::string mid = *stats.mid;
1987 std::string transport_id = RTCTransportStatsIDFromTransportChannel(
1988 *stats.transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
1989 // Inbound
1990 for (const cricket::VideoReceiverInfo& video_receiver_info :
1991 track_media_info_map.video_media_info()->receivers) {
1992 if (!video_receiver_info.connected())
1993 continue;
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001994 auto inbound_video = std::make_unique<RTCInboundRTPStreamStats>(
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +01001995 RTCInboundRTPStreamStatsIDFromSSRC(cricket::MEDIA_TYPE_VIDEO,
1996 video_receiver_info.ssrc()),
Steve Anton57858b32018-02-15 15:19:50 -08001997 timestamp_us);
1998 SetInboundRTPStreamStatsFromVideoReceiverInfo(mid, video_receiver_info,
1999 inbound_video.get());
2000 rtc::scoped_refptr<VideoTrackInterface> video_track =
2001 track_media_info_map.GetVideoTrack(video_receiver_info);
2002 if (video_track) {
2003 inbound_video->track_id =
2004 RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
2005 kReceiver,
Niels Möllerafb246b2022-04-20 14:26:50 +02002006 track_media_info_map.GetAttachmentIdByTrack(video_track.get())
2007 .value());
Steve Anton57858b32018-02-15 15:19:50 -08002008 }
2009 inbound_video->transport_id = transport_id;
2010 report->AddStats(std::move(inbound_video));
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +01002011 // TODO(crbug.com/webrtc/12529): Add remote-outbound stats.
Steve Anton57858b32018-02-15 15:19:50 -08002012 }
2013 // Outbound
Henrik Boström4f40fa52019-12-19 13:27:27 +01002014 std::map<std::string, RTCOutboundRTPStreamStats*> video_outbound_rtps;
Steve Anton57858b32018-02-15 15:19:50 -08002015 for (const cricket::VideoSenderInfo& video_sender_info :
Eldar Rello9276e2c2020-06-10 17:53:39 +03002016 track_media_info_map.video_media_info()->senders) {
Steve Anton57858b32018-02-15 15:19:50 -08002017 if (!video_sender_info.connected())
2018 continue;
Mirko Bonadei317a1f02019-09-17 17:06:18 +02002019 auto outbound_video = std::make_unique<RTCOutboundRTPStreamStats>(
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +01002020 RTCOutboundRTPStreamStatsIDFromSSRC(cricket::MEDIA_TYPE_VIDEO,
2021 video_sender_info.ssrc()),
Steve Anton57858b32018-02-15 15:19:50 -08002022 timestamp_us);
Eldar Rello9276e2c2020-06-10 17:53:39 +03002023 SetOutboundRTPStreamStatsFromVideoSenderInfo(mid, video_sender_info,
2024 outbound_video.get());
Steve Anton57858b32018-02-15 15:19:50 -08002025 rtc::scoped_refptr<VideoTrackInterface> video_track =
2026 track_media_info_map.GetVideoTrack(video_sender_info);
2027 if (video_track) {
Henrik Boström646fda02019-05-22 15:49:42 +02002028 int attachment_id =
Niels Möllerafb246b2022-04-20 14:26:50 +02002029 track_media_info_map.GetAttachmentIdByTrack(video_track.get())
2030 .value();
Steve Anton57858b32018-02-15 15:19:50 -08002031 outbound_video->track_id =
Henrik Boström646fda02019-05-22 15:49:42 +02002032 RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(kSender,
2033 attachment_id);
2034 outbound_video->media_source_id =
2035 RTCMediaSourceStatsIDFromKindAndAttachment(cricket::MEDIA_TYPE_VIDEO,
2036 attachment_id);
Steve Anton57858b32018-02-15 15:19:50 -08002037 }
2038 outbound_video->transport_id = transport_id;
Henrik Boström4f40fa52019-12-19 13:27:27 +01002039 video_outbound_rtps.insert(
2040 std::make_pair(outbound_video->id(), outbound_video.get()));
Steve Anton57858b32018-02-15 15:19:50 -08002041 report->AddStats(std::move(outbound_video));
hbos6ded1902016-11-01 01:50:46 -07002042 }
Henrik Boström883eefc2019-05-27 13:40:25 +02002043 // Remote-inbound
2044 // These are Report Block-based, information sent from the remote endpoint,
2045 // providing metrics about our Outbound streams. We take advantage of the fact
2046 // that RTCOutboundRtpStreamStats, RTCCodecStats and RTCTransport have already
2047 // been added to the report.
2048 for (const cricket::VideoSenderInfo& video_sender_info :
2049 track_media_info_map.video_media_info()->senders) {
2050 for (const auto& report_block_data : video_sender_info.report_block_datas) {
2051 report->AddStats(ProduceRemoteInboundRtpStreamStatsFromReportBlockData(
Eldar Relloc07e9042020-07-03 11:08:07 +03002052 report_block_data, cricket::MEDIA_TYPE_VIDEO, video_outbound_rtps,
2053 *report));
Henrik Boström883eefc2019-05-27 13:40:25 +02002054 }
2055 }
hbos6ded1902016-11-01 01:50:46 -07002056}
2057
hbosdf6075a2016-12-19 04:58:02 -08002058void RTCStatsCollector::ProduceTransportStats_n(
Steve Anton5dfde182018-02-06 10:34:40 -08002059 int64_t timestamp_us,
2060 const std::map<std::string, cricket::TransportStats>&
2061 transport_stats_by_name,
hbos2fa7c672016-10-24 04:00:05 -07002062 const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
2063 RTCStatsReport* report) const {
Tomas Gunnarsson67b1fa22021-04-08 15:18:05 +02002064 RTC_DCHECK_RUN_ON(network_thread_);
Henrik Boströme88c95e2020-07-08 11:18:50 +02002065 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
2066
Steve Anton5dfde182018-02-06 10:34:40 -08002067 for (const auto& entry : transport_stats_by_name) {
2068 const std::string& transport_name = entry.first;
2069 const cricket::TransportStats& transport_stats = entry.second;
2070
hbos2fa7c672016-10-24 04:00:05 -07002071 // Get reference to RTCP channel, if it exists.
2072 std::string rtcp_transport_stats_id;
Steve Anton5dfde182018-02-06 10:34:40 -08002073 for (const cricket::TransportChannelStats& channel_stats :
2074 transport_stats.channel_stats) {
Jonas Olssona4d87372019-07-05 19:08:33 +02002075 if (channel_stats.component == cricket::ICE_CANDIDATE_COMPONENT_RTCP) {
hbos2fa7c672016-10-24 04:00:05 -07002076 rtcp_transport_stats_id = RTCTransportStatsIDFromTransportChannel(
Steve Anton5dfde182018-02-06 10:34:40 -08002077 transport_name, channel_stats.component);
hbos2fa7c672016-10-24 04:00:05 -07002078 break;
2079 }
2080 }
2081
2082 // Get reference to local and remote certificates of this transport, if they
2083 // exist.
Steve Anton5dfde182018-02-06 10:34:40 -08002084 const auto& certificate_stats_it =
2085 transport_cert_stats.find(transport_name);
hbos2fa7c672016-10-24 04:00:05 -07002086 RTC_DCHECK(certificate_stats_it != transport_cert_stats.cend());
2087 std::string local_certificate_id;
2088 if (certificate_stats_it->second.local) {
2089 local_certificate_id = RTCCertificateIDFromFingerprint(
2090 certificate_stats_it->second.local->fingerprint);
2091 }
2092 std::string remote_certificate_id;
2093 if (certificate_stats_it->second.remote) {
2094 remote_certificate_id = RTCCertificateIDFromFingerprint(
2095 certificate_stats_it->second.remote->fingerprint);
2096 }
2097
2098 // There is one transport stats for each channel.
Steve Anton5dfde182018-02-06 10:34:40 -08002099 for (const cricket::TransportChannelStats& channel_stats :
2100 transport_stats.channel_stats) {
hbos2fa7c672016-10-24 04:00:05 -07002101 std::unique_ptr<RTCTransportStats> transport_stats(
Steve Anton5dfde182018-02-06 10:34:40 -08002102 new RTCTransportStats(RTCTransportStatsIDFromTransportChannel(
2103 transport_name, channel_stats.component),
2104 timestamp_us));
Jonas Oreland42da5a92022-03-01 13:55:37 +01002105 transport_stats->packets_sent =
2106 channel_stats.ice_transport_stats.packets_sent;
2107 transport_stats->packets_received =
2108 channel_stats.ice_transport_stats.packets_received;
2109 transport_stats->bytes_sent =
2110 channel_stats.ice_transport_stats.bytes_sent;
2111 transport_stats->bytes_received =
2112 channel_stats.ice_transport_stats.bytes_received;
Jonas Olssona4d87372019-07-05 19:08:33 +02002113 transport_stats->dtls_state =
2114 DtlsTransportStateToRTCDtlsTransportState(channel_stats.dtls_state);
Jonas Oreland149dc722019-08-28 08:10:27 +02002115 transport_stats->selected_candidate_pair_changes =
2116 channel_stats.ice_transport_stats.selected_candidate_pair_changes;
Philipp Hanckecc1b9b02022-05-04 18:58:26 +02002117 transport_stats->ice_role =
2118 IceRoleToRTCIceRole(channel_stats.ice_transport_stats.ice_role);
Philipp Hancke95b1a342022-05-05 07:53:54 +02002119 transport_stats->ice_local_username_fragment =
2120 channel_stats.ice_transport_stats.ice_local_username_fragment;
hbos2fa7c672016-10-24 04:00:05 -07002121 for (const cricket::ConnectionInfo& info :
Jonas Oreland149dc722019-08-28 08:10:27 +02002122 channel_stats.ice_transport_stats.connection_infos) {
hbos2fa7c672016-10-24 04:00:05 -07002123 if (info.best_connection) {
hbos2fa7c672016-10-24 04:00:05 -07002124 transport_stats->selected_candidate_pair_id =
2125 RTCIceCandidatePairStatsIDFromConnectionInfo(info);
2126 }
2127 }
2128 if (channel_stats.component != cricket::ICE_CANDIDATE_COMPONENT_RTCP &&
2129 !rtcp_transport_stats_id.empty()) {
2130 transport_stats->rtcp_transport_stats_id = rtcp_transport_stats_id;
2131 }
2132 if (!local_certificate_id.empty())
2133 transport_stats->local_certificate_id = local_certificate_id;
2134 if (!remote_certificate_id.empty())
2135 transport_stats->remote_certificate_id = remote_certificate_id;
Harald Alvestrand5cb78072019-10-28 09:51:17 +01002136 // Crypto information
2137 if (channel_stats.ssl_version_bytes) {
2138 char bytes[5];
2139 snprintf(bytes, sizeof(bytes), "%04X", channel_stats.ssl_version_bytes);
2140 transport_stats->tls_version = bytes;
2141 }
Philipp Hancke69c1df22022-04-22 15:46:24 +02002142
2143 if (channel_stats.dtls_role) {
2144 transport_stats->dtls_role = *channel_stats.dtls_role == rtc::SSL_CLIENT
2145 ? webrtc::RTCDtlsRole::kClient
2146 : webrtc::RTCDtlsRole::kServer;
2147 } else {
2148 transport_stats->dtls_role = webrtc::RTCDtlsRole::kUnknown;
2149 }
2150
Mirko Bonadei7750d802021-07-26 17:27:42 +02002151 if (channel_stats.ssl_cipher_suite != rtc::kTlsNullWithNullNull &&
Harald Alvestrand5cb78072019-10-28 09:51:17 +01002152 rtc::SSLStreamAdapter::SslCipherSuiteToName(
2153 channel_stats.ssl_cipher_suite)
2154 .length()) {
2155 transport_stats->dtls_cipher =
2156 rtc::SSLStreamAdapter::SslCipherSuiteToName(
2157 channel_stats.ssl_cipher_suite);
2158 }
Mirko Bonadei7750d802021-07-26 17:27:42 +02002159 if (channel_stats.srtp_crypto_suite != rtc::kSrtpInvalidCryptoSuite &&
Harald Alvestrand5cb78072019-10-28 09:51:17 +01002160 rtc::SrtpCryptoSuiteToName(channel_stats.srtp_crypto_suite)
2161 .length()) {
2162 transport_stats->srtp_cipher =
2163 rtc::SrtpCryptoSuiteToName(channel_stats.srtp_crypto_suite);
2164 }
hbos2fa7c672016-10-24 04:00:05 -07002165 report->AddStats(std::move(transport_stats));
2166 }
2167 }
2168}
2169
2170std::map<std::string, RTCStatsCollector::CertificateStatsPair>
hbosdf6075a2016-12-19 04:58:02 -08002171RTCStatsCollector::PrepareTransportCertificateStats_n(
Steve Anton5dfde182018-02-06 10:34:40 -08002172 const std::map<std::string, cricket::TransportStats>&
2173 transport_stats_by_name) const {
Tomas Gunnarsson67b1fa22021-04-08 15:18:05 +02002174 RTC_DCHECK_RUN_ON(network_thread_);
Henrik Boströme88c95e2020-07-08 11:18:50 +02002175 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
2176
hbos2fa7c672016-10-24 04:00:05 -07002177 std::map<std::string, CertificateStatsPair> transport_cert_stats;
Steve Anton5dfde182018-02-06 10:34:40 -08002178 for (const auto& entry : transport_stats_by_name) {
2179 const std::string& transport_name = entry.first;
2180
hbos2fa7c672016-10-24 04:00:05 -07002181 CertificateStatsPair certificate_stats_pair;
2182 rtc::scoped_refptr<rtc::RTCCertificate> local_certificate;
Steve Anton5dfde182018-02-06 10:34:40 -08002183 if (pc_->GetLocalCertificate(transport_name, &local_certificate)) {
hbos2fa7c672016-10-24 04:00:05 -07002184 certificate_stats_pair.local =
Benjamin Wright6c6c9df2018-10-25 01:16:26 -07002185 local_certificate->GetSSLCertificateChain().GetStats();
hbos2fa7c672016-10-24 04:00:05 -07002186 }
Steve Anton5dfde182018-02-06 10:34:40 -08002187
Taylor Brandstetterc3928662018-02-23 13:04:51 -08002188 std::unique_ptr<rtc::SSLCertChain> remote_cert_chain =
2189 pc_->GetRemoteSSLCertChain(transport_name);
2190 if (remote_cert_chain) {
2191 certificate_stats_pair.remote = remote_cert_chain->GetStats();
hbos2fa7c672016-10-24 04:00:05 -07002192 }
Steve Anton5dfde182018-02-06 10:34:40 -08002193
hbos2fa7c672016-10-24 04:00:05 -07002194 transport_cert_stats.insert(
Steve Anton5dfde182018-02-06 10:34:40 -08002195 std::make_pair(transport_name, std::move(certificate_stats_pair)));
hbos2fa7c672016-10-24 04:00:05 -07002196 }
2197 return transport_cert_stats;
2198}
2199
Tomas Gunnarssonbfd9ba82021-04-18 11:55:57 +02002200void RTCStatsCollector::PrepareTransceiverStatsInfosAndCallStats_s_w_n() {
Tomas Gunnarsson67b1fa22021-04-08 15:18:05 +02002201 RTC_DCHECK_RUN_ON(signaling_thread_);
Steve Anton56bae8d2018-02-14 16:07:42 -08002202
Henrik Boström180faeb2020-11-13 09:05:21 +01002203 transceiver_stats_infos_.clear();
Steve Anton57858b32018-02-15 15:19:50 -08002204 // These are used to invoke GetStats for all the media channels together in
2205 // one worker thread hop.
Harald Alvestranda4e94802022-04-30 16:09:52 +00002206 std::map<cricket::MediaChannel*, std::unique_ptr<cricket::VoiceMediaInfo>>
Steve Anton57858b32018-02-15 15:19:50 -08002207 voice_stats;
Harald Alvestranda4e94802022-04-30 16:09:52 +00002208 std::map<cricket::MediaChannel*, std::unique_ptr<cricket::VideoMediaInfo>>
Steve Anton57858b32018-02-15 15:19:50 -08002209 video_stats;
2210
Tomas Gunnarssonbfd9ba82021-04-18 11:55:57 +02002211 auto transceivers = pc_->GetTransceiversInternal();
2212
2213 // TODO(tommi): See if we can avoid synchronously blocking the signaling
2214 // thread while we do this (or avoid the Invoke at all).
2215 network_thread_->Invoke<void>(RTC_FROM_HERE, [this, &transceivers,
2216 &voice_stats, &video_stats] {
Henrik Boströme88c95e2020-07-08 11:18:50 +02002217 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
Steve Anton57858b32018-02-15 15:19:50 -08002218
Tomas Gunnarssonbfd9ba82021-04-18 11:55:57 +02002219 for (const auto& transceiver_proxy : transceivers) {
2220 RtpTransceiver* transceiver = transceiver_proxy->internal();
Henrik Boströme88c95e2020-07-08 11:18:50 +02002221 cricket::MediaType media_type = transceiver->media_type();
Steve Anton57858b32018-02-15 15:19:50 -08002222
Henrik Boströme88c95e2020-07-08 11:18:50 +02002223 // Prepare stats entry. The TrackMediaInfoMap will be filled in after the
2224 // stats have been fetched on the worker thread.
Henrik Boström180faeb2020-11-13 09:05:21 +01002225 transceiver_stats_infos_.emplace_back();
2226 RtpTransceiverStatsInfo& stats = transceiver_stats_infos_.back();
Tomas Gunnarssonbfd9ba82021-04-18 11:55:57 +02002227 stats.transceiver = transceiver;
Henrik Boströme88c95e2020-07-08 11:18:50 +02002228 stats.media_type = media_type;
Steve Anton57858b32018-02-15 15:19:50 -08002229
Tomas Gunnarssonbfd9ba82021-04-18 11:55:57 +02002230 cricket::ChannelInterface* channel = transceiver->channel();
Henrik Boströme88c95e2020-07-08 11:18:50 +02002231 if (!channel) {
2232 // The remaining fields require a BaseChannel.
2233 continue;
2234 }
Steve Anton57858b32018-02-15 15:19:50 -08002235
Tomas Gunnarsson5411b172022-01-24 08:45:26 +01002236 stats.mid = channel->mid();
Tomas Gunnarsson94f01942022-01-03 14:59:12 +00002237 stats.transport_name = std::string(channel->transport_name());
Henrik Boströme88c95e2020-07-08 11:18:50 +02002238
2239 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
Harald Alvestranda4e94802022-04-30 16:09:52 +00002240 RTC_DCHECK(voice_stats.find(channel->media_channel()) ==
Henrik Boströme88c95e2020-07-08 11:18:50 +02002241 voice_stats.end());
Harald Alvestranda4e94802022-04-30 16:09:52 +00002242 voice_stats[channel->media_channel()] =
Henrik Boströme88c95e2020-07-08 11:18:50 +02002243 std::make_unique<cricket::VoiceMediaInfo>();
2244 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
Harald Alvestranda4e94802022-04-30 16:09:52 +00002245 RTC_DCHECK(video_stats.find(channel->media_channel()) ==
Henrik Boströme88c95e2020-07-08 11:18:50 +02002246 video_stats.end());
Harald Alvestranda4e94802022-04-30 16:09:52 +00002247 video_stats[channel->media_channel()] =
Henrik Boströme88c95e2020-07-08 11:18:50 +02002248 std::make_unique<cricket::VideoMediaInfo>();
2249 } else {
Artem Titovd3251962021-11-15 16:57:07 +01002250 RTC_DCHECK_NOTREACHED();
Henrik Boströme88c95e2020-07-08 11:18:50 +02002251 }
Steve Anton57858b32018-02-15 15:19:50 -08002252 }
Tomas Gunnarssonbfd9ba82021-04-18 11:55:57 +02002253 });
Steve Anton57858b32018-02-15 15:19:50 -08002254
Henrik Boström180faeb2020-11-13 09:05:21 +01002255 // We jump to the worker thread and call GetStats() on each media channel as
2256 // well as GetCallStats(). At the same time we construct the
2257 // TrackMediaInfoMaps, which also needs info from the worker thread. This
2258 // minimizes the number of thread jumps.
Steve Anton57858b32018-02-15 15:19:50 -08002259 worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
Henrik Boström6fafbe32020-07-08 10:37:00 +02002260 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
2261
Steve Anton57858b32018-02-15 15:19:50 -08002262 for (const auto& entry : voice_stats) {
Harald Alvestranda4e94802022-04-30 16:09:52 +00002263 if (!static_cast<cricket::VoiceMediaChannel*>(entry.first)
2264 ->GetStats(entry.second.get(),
2265 /*get_and_clear_legacy_stats=*/false)) {
Steve Anton57858b32018-02-15 15:19:50 -08002266 RTC_LOG(LS_WARNING) << "Failed to get voice stats.";
2267 }
2268 }
2269 for (const auto& entry : video_stats) {
Harald Alvestranda4e94802022-04-30 16:09:52 +00002270 if (!static_cast<cricket::VideoMediaChannel*>(entry.first)
2271 ->GetStats(entry.second.get())) {
Steve Anton57858b32018-02-15 15:19:50 -08002272 RTC_LOG(LS_WARNING) << "Failed to get video stats.";
2273 }
2274 }
Steve Anton57858b32018-02-15 15:19:50 -08002275
Henrik Boström6fafbe32020-07-08 10:37:00 +02002276 // Create the TrackMediaInfoMap for each transceiver stats object.
Henrik Boström180faeb2020-11-13 09:05:21 +01002277 for (auto& stats : transceiver_stats_infos_) {
Henrik Boström6fafbe32020-07-08 10:37:00 +02002278 auto transceiver = stats.transceiver;
2279 std::unique_ptr<cricket::VoiceMediaInfo> voice_media_info;
2280 std::unique_ptr<cricket::VideoMediaInfo> video_media_info;
Harald Alvestranda4e94802022-04-30 16:09:52 +00002281 auto channel = transceiver->channel();
2282 if (channel) {
Henrik Boström6fafbe32020-07-08 10:37:00 +02002283 cricket::MediaType media_type = transceiver->media_type();
2284 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
Harald Alvestranda4e94802022-04-30 16:09:52 +00002285 RTC_DCHECK(voice_stats[channel->media_channel()]);
2286 voice_media_info = std::move(voice_stats[channel->media_channel()]);
Henrik Boström6fafbe32020-07-08 10:37:00 +02002287 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
Harald Alvestranda4e94802022-04-30 16:09:52 +00002288 RTC_DCHECK(video_stats[channel->media_channel()]);
2289 video_media_info = std::move(video_stats[channel->media_channel()]);
Henrik Boström6fafbe32020-07-08 10:37:00 +02002290 }
Steve Anton57858b32018-02-15 15:19:50 -08002291 }
Henrik Boström6fafbe32020-07-08 10:37:00 +02002292 std::vector<rtc::scoped_refptr<RtpSenderInternal>> senders;
2293 for (const auto& sender : transceiver->senders()) {
Niels Möllere7cc8832022-01-04 15:20:03 +01002294 senders.push_back(
2295 rtc::scoped_refptr<RtpSenderInternal>(sender->internal()));
Henrik Boström6fafbe32020-07-08 10:37:00 +02002296 }
2297 std::vector<rtc::scoped_refptr<RtpReceiverInternal>> receivers;
2298 for (const auto& receiver : transceiver->receivers()) {
Niels Möllere7cc8832022-01-04 15:20:03 +01002299 receivers.push_back(
2300 rtc::scoped_refptr<RtpReceiverInternal>(receiver->internal()));
Henrik Boström6fafbe32020-07-08 10:37:00 +02002301 }
2302 stats.track_media_info_map = std::make_unique<TrackMediaInfoMap>(
2303 std::move(voice_media_info), std::move(video_media_info), senders,
2304 receivers);
Steve Anton57858b32018-02-15 15:19:50 -08002305 }
Steve Anton57858b32018-02-15 15:19:50 -08002306
Henrik Boström180faeb2020-11-13 09:05:21 +01002307 call_stats_ = pc_->GetCallStats();
2308 });
hbos0adb8282016-11-23 02:32:06 -08002309}
2310
Taylor Brandstetter3a034e12020-07-09 15:32:34 -07002311void RTCStatsCollector::OnSctpDataChannelCreated(SctpDataChannel* channel) {
2312 channel->SignalOpened.connect(this, &RTCStatsCollector::OnDataChannelOpened);
2313 channel->SignalClosed.connect(this, &RTCStatsCollector::OnDataChannelClosed);
2314}
2315
2316void RTCStatsCollector::OnDataChannelOpened(DataChannelInterface* channel) {
Tomas Gunnarsson67b1fa22021-04-08 15:18:05 +02002317 RTC_DCHECK_RUN_ON(signaling_thread_);
Jonas Olssona4d87372019-07-05 19:08:33 +02002318 bool result = internal_record_.opened_data_channels
2319 .insert(reinterpret_cast<uintptr_t>(channel))
2320 .second;
hbos82ebe022016-11-14 01:41:09 -08002321 ++internal_record_.data_channels_opened;
2322 RTC_DCHECK(result);
2323}
2324
Taylor Brandstetter3a034e12020-07-09 15:32:34 -07002325void RTCStatsCollector::OnDataChannelClosed(DataChannelInterface* channel) {
Tomas Gunnarsson67b1fa22021-04-08 15:18:05 +02002326 RTC_DCHECK_RUN_ON(signaling_thread_);
hbos82ebe022016-11-14 01:41:09 -08002327 // Only channels that have been fully opened (and have increased the
Artem Titov880fa812021-07-30 22:30:23 +02002328 // `data_channels_opened_` counter) increase the closed counter.
hbos5bf9def2017-03-20 03:14:14 -07002329 if (internal_record_.opened_data_channels.erase(
2330 reinterpret_cast<uintptr_t>(channel))) {
hbos82ebe022016-11-14 01:41:09 -08002331 ++internal_record_.data_channels_closed;
2332 }
2333}
2334
hboscc555c52016-10-18 12:48:31 -07002335const char* CandidateTypeToRTCIceCandidateTypeForTesting(
2336 const std::string& type) {
2337 return CandidateTypeToRTCIceCandidateType(type);
2338}
2339
2340const char* DataStateToRTCDataChannelStateForTesting(
2341 DataChannelInterface::DataState state) {
2342 return DataStateToRTCDataChannelState(state);
2343}
2344
hbosd565b732016-08-30 14:04:35 -07002345} // namespace webrtc