blob: f0070dfda6c34500f4c13a747267ed6e68910d84 [file] [log] [blame]
hbosd565b732016-08-30 21:04:351/*
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 17:11:0011#include "pc/rtc_stats_collector.h"
hbosd565b732016-08-30 21:04:3512
Harald Alvestrandc24a2182022-02-23 13:44:5913#include <stdint.h>
Harald Alvestrand5761e7b2021-01-29 14:45:0814#include <stdio.h>
Artem Titovd15a5752021-02-10 13:31:2415
Harald Alvestrand5761e7b2021-01-29 14:45:0816#include <cstdint>
Johannes Kron72d69152020-02-10 13:05:5517#include <map>
hbosd565b732016-08-30 21:04:3518#include <memory>
Steve Anton36b29d12017-10-30 16:57:4219#include <string>
Harald Alvestrandc24a2182022-02-23 13:44:5920#include <type_traits>
hbosd565b732016-08-30 21:04:3521#include <utility>
22#include <vector>
23
Danil Chapovalova30439b2022-07-07 08:08:4924#include "absl/functional/bind_front.h"
Harald Alvestrandc24a2182022-02-23 13:44:5925#include "absl/strings/string_view.h"
Harald Alvestrand5761e7b2021-01-29 14:45:0826#include "api/array_view.h"
Patrik Höglunde2d6a062017-10-05 12:53:3327#include "api/candidate.h"
Harald Alvestrandc24a2182022-02-23 13:44:5928#include "api/dtls_transport_interface.h"
Steve Anton10542f22019-01-11 17:11:0029#include "api/media_stream_interface.h"
Harald Alvestrand5761e7b2021-01-29 14:45:0830#include "api/rtp_parameters.h"
Artem Titovd15a5752021-02-10 13:31:2431#include "api/sequence_checker.h"
Harald Alvestrand5761e7b2021-01-29 14:45:0832#include "api/stats/rtc_stats.h"
33#include "api/stats/rtcstats_objects.h"
Harald Alvestrandc24a2182022-02-23 13:44:5934#include "api/units/time_delta.h"
Henrik Boström2e069262019-04-09 11:59:3135#include "api/video/video_content_type.h"
Harald Alvestrand5761e7b2021-01-29 14:45:0836#include "common_video/include/quality_limitation_reason.h"
Steve Anton10542f22019-01-11 17:11:0037#include "media/base/media_channel.h"
Harald Alvestrand5761e7b2021-01-29 14:45:0838#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:0842#include "p2p/base/ice_transport_internal.h"
Steve Anton10542f22019-01-11 17:11:0043#include "p2p/base/p2p_constants.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3144#include "p2p/base/port.h"
Harald Alvestrand5761e7b2021-01-29 14:45:0845#include "pc/channel_interface.h"
46#include "pc/data_channel_utils.h"
Steve Anton10542f22019-01-11 17:11:0047#include "pc/rtc_stats_traversal.h"
Harald Alvestrandc24a2182022-02-23 13:44:5948#include "pc/rtp_receiver_proxy.h"
49#include "pc/rtp_sender_proxy.h"
Johannes Kron72d69152020-02-10 13:05:5550#include "pc/webrtc_sdp.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3151#include "rtc_base/checks.h"
Harald Alvestrand5761e7b2021-01-29 14:45:0852#include "rtc_base/ip_address.h"
Harald Alvestrand5761e7b2021-01-29 14:45:0853#include "rtc_base/logging.h"
54#include "rtc_base/network_constants.h"
Harald Alvestrand5761e7b2021-01-29 14:45:0855#include "rtc_base/rtc_certificate.h"
56#include "rtc_base/socket_address.h"
57#include "rtc_base/ssl_stream_adapter.h"
58#include "rtc_base/string_encode.h"
Jonas Olsson43568dd2018-06-11 14:25:5459#include "rtc_base/strings/string_builder.h"
Steve Anton10542f22019-01-11 17:11:0060#include "rtc_base/time_utils.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3161#include "rtc_base/trace_event.h"
hbosd565b732016-08-30 21:04:3562
63namespace webrtc {
64
hboscc555c52016-10-18 19:48:3165namespace {
66
Henrik Boström8dfc90f2022-09-02 07:39:2967const char kDirectionInbound = 'I';
68const char kDirectionOutbound = 'O';
69
Henrik Boström646fda02019-05-22 13:49:4270// TODO(https://crbug.com/webrtc/10656): Consider making IDs less predictable.
hbos2fa7c672016-10-24 11:00:0571std::string RTCCertificateIDFromFingerprint(const std::string& fingerprint) {
Henrik Boström8dfc90f2022-09-02 07:39:2972 return "CF" + fingerprint;
hbos2fa7c672016-10-24 11:00:0573}
74
Henrik Boström8dfc90f2022-09-02 07:39:2975// `direction` is either kDirectionInbound or kDirectionOutbound.
Henrik Boströmb2be3922022-09-02 07:37:0876std::string RTCCodecStatsIDFromTransportAndCodecParameters(
Henrik Boström8dfc90f2022-09-02 07:39:2977 const char direction,
Henrik Boströmb2be3922022-09-02 07:37:0878 const std::string& transport_id,
Henrik Boströmb2be3922022-09-02 07:37:0879 const RtpCodecParameters& codec_params) {
Jonas Olsson43568dd2018-06-11 14:25:5480 char buf[1024];
81 rtc::SimpleStringBuilder sb(buf);
Henrik Boström8dfc90f2022-09-02 07:39:2982 sb << 'C' << direction << transport_id << '_' << codec_params.payload_type;
Henrik Boström31c373b2022-09-26 12:56:2183 // TODO(https://crbug.com/webrtc/14420): If we stop supporting different FMTP
84 // lines for the same PT and transport, which should be illegal SDP, then we
85 // wouldn't need `fmtp` to be part of the ID here.
Henrik Boströmb2be3922022-09-02 07:37:0886 rtc::StringBuilder fmtp;
87 if (WriteFmtpParameters(codec_params.parameters, &fmtp)) {
Henrik Boström8dfc90f2022-09-02 07:39:2988 sb << '_' << fmtp.Release();
Henrik Boströmb2be3922022-09-02 07:37:0889 }
Jonas Olsson43568dd2018-06-11 14:25:5490 return sb.str();
hbos0adb8282016-11-23 10:32:0691}
92
hbos2fa7c672016-10-24 11:00:0593std::string RTCIceCandidatePairStatsIDFromConnectionInfo(
94 const cricket::ConnectionInfo& info) {
Jonas Olsson43568dd2018-06-11 14:25:5495 char buf[4096];
96 rtc::SimpleStringBuilder sb(buf);
Henrik Boström8dfc90f2022-09-02 07:39:2997 sb << "CP" << info.local_candidate.id() << "_" << info.remote_candidate.id();
Jonas Olsson43568dd2018-06-11 14:25:5498 return sb.str();
hbos2fa7c672016-10-24 11:00:0599}
100
Henrik Boström8dfc90f2022-09-02 07:39:29101// `direction` is either kDirectionInbound or kDirectionOutbound.
Henrik Boström15166b22022-10-19 09:06:58102std::string DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
Henrik Boström8dfc90f2022-09-02 07:39:29103 const char direction,
Harald Alvestrandc72af932018-01-11 16:18:19104 int attachment_id) {
Jonas Olsson43568dd2018-06-11 14:25:54105 char buf[1024];
106 rtc::SimpleStringBuilder sb(buf);
Henrik Boström8dfc90f2022-09-02 07:39:29107 sb << "DEPRECATED_T" << direction << attachment_id;
Jonas Olsson43568dd2018-06-11 14:25:54108 return sb.str();
hbos09bc1282016-11-08 14:29:22109}
110
hbos2fa7c672016-10-24 11:00:05111std::string RTCTransportStatsIDFromTransportChannel(
Jonas Olssona4d87372019-07-05 17:08:33112 const std::string& transport_name,
113 int channel_component) {
Jonas Olsson43568dd2018-06-11 14:25:54114 char buf[1024];
115 rtc::SimpleStringBuilder sb(buf);
Henrik Boström8dfc90f2022-09-02 07:39:29116 sb << 'T' << transport_name << channel_component;
Jonas Olsson43568dd2018-06-11 14:25:54117 return sb.str();
hbos2fa7c672016-10-24 11:00:05118}
119
Henrik Boströmb43e3bb2022-09-26 10:36:44120std::string RTCInboundRTPStreamStatsIDFromSSRC(const std::string& transport_id,
121 cricket::MediaType media_type,
Alessio Bazzicaf7b1b952021-03-23 16:23:04122 uint32_t ssrc) {
Jonas Olsson43568dd2018-06-11 14:25:54123 char buf[1024];
124 rtc::SimpleStringBuilder sb(buf);
Henrik Boströmb43e3bb2022-09-26 10:36:44125 sb << 'I' << transport_id
126 << (media_type == cricket::MEDIA_TYPE_AUDIO ? 'A' : 'V') << ssrc;
Jonas Olsson43568dd2018-06-11 14:25:54127 return sb.str();
hboseeafe942016-11-01 10:00:17128}
129
Henrik Boströmb43e3bb2022-09-26 10:36:44130std::string RTCOutboundRTPStreamStatsIDFromSSRC(const std::string& transport_id,
131 cricket::MediaType media_type,
Alessio Bazzicaf7b1b952021-03-23 16:23:04132 uint32_t ssrc) {
Jonas Olsson43568dd2018-06-11 14:25:54133 char buf[1024];
134 rtc::SimpleStringBuilder sb(buf);
Henrik Boströmb43e3bb2022-09-26 10:36:44135 sb << 'O' << transport_id
136 << (media_type == cricket::MEDIA_TYPE_AUDIO ? 'A' : 'V') << ssrc;
Jonas Olsson43568dd2018-06-11 14:25:54137 return sb.str();
hbos6ded1902016-11-01 08:50:46138}
139
Henrik Boström8605fbf2019-06-24 14:44:51140std::string RTCRemoteInboundRtpStreamStatsIdFromSourceSsrc(
Henrik Boström883eefc2019-05-27 11:40:25141 cricket::MediaType media_type,
Henrik Boström883eefc2019-05-27 11:40:25142 uint32_t source_ssrc) {
143 char buf[1024];
144 rtc::SimpleStringBuilder sb(buf);
Henrik Boström8dfc90f2022-09-02 07:39:29145 sb << "RI" << (media_type == cricket::MEDIA_TYPE_AUDIO ? 'A' : 'V')
146 << source_ssrc;
Henrik Boström883eefc2019-05-27 11:40:25147 return sb.str();
148}
149
Alessio Bazzicaf7b1b952021-03-23 16:23:04150std::string RTCRemoteOutboundRTPStreamStatsIDFromSSRC(
151 cricket::MediaType media_type,
152 uint32_t source_ssrc) {
153 char buf[1024];
154 rtc::SimpleStringBuilder sb(buf);
Henrik Boström8dfc90f2022-09-02 07:39:29155 sb << "RO" << (media_type == cricket::MEDIA_TYPE_AUDIO ? 'A' : 'V')
156 << source_ssrc;
Alessio Bazzicaf7b1b952021-03-23 16:23:04157 return sb.str();
158}
159
Henrik Boström646fda02019-05-22 13:49:42160std::string RTCMediaSourceStatsIDFromKindAndAttachment(
161 cricket::MediaType media_type,
162 int attachment_id) {
163 char buf[1024];
164 rtc::SimpleStringBuilder sb(buf);
Henrik Boström8dfc90f2022-09-02 07:39:29165 sb << 'S' << (media_type == cricket::MEDIA_TYPE_AUDIO ? 'A' : 'V')
166 << attachment_id;
Henrik Boström646fda02019-05-22 13:49:42167 return sb.str();
168}
169
hbosab9f6e42016-10-07 09:18:47170const char* CandidateTypeToRTCIceCandidateType(const std::string& type) {
171 if (type == cricket::LOCAL_PORT_TYPE)
172 return RTCIceCandidateType::kHost;
173 if (type == cricket::STUN_PORT_TYPE)
174 return RTCIceCandidateType::kSrflx;
175 if (type == cricket::PRFLX_PORT_TYPE)
176 return RTCIceCandidateType::kPrflx;
177 if (type == cricket::RELAY_PORT_TYPE)
178 return RTCIceCandidateType::kRelay;
Artem Titovd3251962021-11-15 15:57:07179 RTC_DCHECK_NOTREACHED();
hbosab9f6e42016-10-07 09:18:47180 return nullptr;
181}
182
hboscc555c52016-10-18 19:48:31183const char* DataStateToRTCDataChannelState(
184 DataChannelInterface::DataState state) {
185 switch (state) {
186 case DataChannelInterface::kConnecting:
187 return RTCDataChannelState::kConnecting;
188 case DataChannelInterface::kOpen:
189 return RTCDataChannelState::kOpen;
190 case DataChannelInterface::kClosing:
191 return RTCDataChannelState::kClosing;
192 case DataChannelInterface::kClosed:
193 return RTCDataChannelState::kClosed;
194 default:
Artem Titovd3251962021-11-15 15:57:07195 RTC_DCHECK_NOTREACHED();
hboscc555c52016-10-18 19:48:31196 return nullptr;
197 }
198}
199
hbos06495bc2017-01-02 16:08:18200const char* IceCandidatePairStateToRTCStatsIceCandidatePairState(
201 cricket::IceCandidatePairState state) {
202 switch (state) {
203 case cricket::IceCandidatePairState::WAITING:
204 return RTCStatsIceCandidatePairState::kWaiting;
205 case cricket::IceCandidatePairState::IN_PROGRESS:
206 return RTCStatsIceCandidatePairState::kInProgress;
207 case cricket::IceCandidatePairState::SUCCEEDED:
208 return RTCStatsIceCandidatePairState::kSucceeded;
209 case cricket::IceCandidatePairState::FAILED:
210 return RTCStatsIceCandidatePairState::kFailed;
211 default:
Artem Titovd3251962021-11-15 15:57:07212 RTC_DCHECK_NOTREACHED();
hbos06495bc2017-01-02 16:08:18213 return nullptr;
214 }
215}
216
Philipp Hanckecc1b9b02022-05-04 16:58:26217const char* IceRoleToRTCIceRole(cricket::IceRole role) {
218 switch (role) {
219 case cricket::IceRole::ICEROLE_UNKNOWN:
220 return RTCIceRole::kUnknown;
221 case cricket::IceRole::ICEROLE_CONTROLLED:
222 return RTCIceRole::kControlled;
223 case cricket::IceRole::ICEROLE_CONTROLLING:
224 return RTCIceRole::kControlling;
225 default:
226 RTC_DCHECK_NOTREACHED();
227 return nullptr;
228 }
229}
230
hbos7064d592017-01-16 15:38:02231const char* DtlsTransportStateToRTCDtlsTransportState(
Mirko Bonadei9f6808b2021-05-21 18:46:09232 DtlsTransportState state) {
hbos7064d592017-01-16 15:38:02233 switch (state) {
Mirko Bonadei9f6808b2021-05-21 18:46:09234 case DtlsTransportState::kNew:
hbos7064d592017-01-16 15:38:02235 return RTCDtlsTransportState::kNew;
Mirko Bonadei9f6808b2021-05-21 18:46:09236 case DtlsTransportState::kConnecting:
hbos7064d592017-01-16 15:38:02237 return RTCDtlsTransportState::kConnecting;
Mirko Bonadei9f6808b2021-05-21 18:46:09238 case DtlsTransportState::kConnected:
hbos7064d592017-01-16 15:38:02239 return RTCDtlsTransportState::kConnected;
Mirko Bonadei9f6808b2021-05-21 18:46:09240 case DtlsTransportState::kClosed:
hbos7064d592017-01-16 15:38:02241 return RTCDtlsTransportState::kClosed;
Mirko Bonadei9f6808b2021-05-21 18:46:09242 case DtlsTransportState::kFailed:
hbos7064d592017-01-16 15:38:02243 return RTCDtlsTransportState::kFailed;
244 default:
Mirko Bonadei9f6808b2021-05-21 18:46:09245 RTC_CHECK_NOTREACHED();
hbos7064d592017-01-16 15:38:02246 return nullptr;
247 }
248}
249
Philipp Hancke1f491572022-05-09 15:43:31250const char* IceTransportStateToRTCIceTransportState(IceTransportState state) {
251 switch (state) {
252 case IceTransportState::kNew:
253 return RTCIceTransportState::kNew;
254 case IceTransportState::kChecking:
255 return RTCIceTransportState::kChecking;
256 case IceTransportState::kConnected:
257 return RTCIceTransportState::kConnected;
258 case IceTransportState::kCompleted:
259 return RTCIceTransportState::kCompleted;
260 case IceTransportState::kFailed:
261 return RTCIceTransportState::kFailed;
262 case IceTransportState::kDisconnected:
263 return RTCIceTransportState::kDisconnected;
264 case IceTransportState::kClosed:
265 return RTCIceTransportState::kClosed;
266 default:
267 RTC_CHECK_NOTREACHED();
268 return nullptr;
269 }
270}
271
Jonas Oreland0d13bbd2022-03-02 10:17:36272const char* NetworkTypeToStatsType(rtc::AdapterType type) {
Gary Liu37e489c2017-11-21 18:49:36273 switch (type) {
274 case rtc::ADAPTER_TYPE_CELLULAR:
Jonas Oreland08d18062020-04-02 05:19:12275 case rtc::ADAPTER_TYPE_CELLULAR_2G:
276 case rtc::ADAPTER_TYPE_CELLULAR_3G:
277 case rtc::ADAPTER_TYPE_CELLULAR_4G:
278 case rtc::ADAPTER_TYPE_CELLULAR_5G:
Gary Liu37e489c2017-11-21 18:49:36279 return RTCNetworkType::kCellular;
280 case rtc::ADAPTER_TYPE_ETHERNET:
281 return RTCNetworkType::kEthernet;
282 case rtc::ADAPTER_TYPE_WIFI:
283 return RTCNetworkType::kWifi;
284 case rtc::ADAPTER_TYPE_VPN:
285 return RTCNetworkType::kVpn;
286 case rtc::ADAPTER_TYPE_UNKNOWN:
287 case rtc::ADAPTER_TYPE_LOOPBACK:
Qingsi Wang9f1de692018-06-28 22:38:09288 case rtc::ADAPTER_TYPE_ANY:
Gary Liu37e489c2017-11-21 18:49:36289 return RTCNetworkType::kUnknown;
290 }
Artem Titovd3251962021-11-15 15:57:07291 RTC_DCHECK_NOTREACHED();
Gary Liu37e489c2017-11-21 18:49:36292 return nullptr;
293}
294
Jonas Oreland0d13bbd2022-03-02 10:17:36295absl::string_view NetworkTypeToStatsNetworkAdapterType(rtc::AdapterType type) {
296 switch (type) {
297 case rtc::ADAPTER_TYPE_CELLULAR:
298 return RTCNetworkAdapterType::kCellular;
299 case rtc::ADAPTER_TYPE_CELLULAR_2G:
300 return RTCNetworkAdapterType::kCellular2g;
301 case rtc::ADAPTER_TYPE_CELLULAR_3G:
302 return RTCNetworkAdapterType::kCellular3g;
303 case rtc::ADAPTER_TYPE_CELLULAR_4G:
304 return RTCNetworkAdapterType::kCellular4g;
305 case rtc::ADAPTER_TYPE_CELLULAR_5G:
306 return RTCNetworkAdapterType::kCellular5g;
307 case rtc::ADAPTER_TYPE_ETHERNET:
308 return RTCNetworkAdapterType::kEthernet;
309 case rtc::ADAPTER_TYPE_WIFI:
310 return RTCNetworkAdapterType::kWifi;
311 case rtc::ADAPTER_TYPE_UNKNOWN:
312 return RTCNetworkAdapterType::kUnknown;
313 case rtc::ADAPTER_TYPE_LOOPBACK:
314 return RTCNetworkAdapterType::kLoopback;
315 case rtc::ADAPTER_TYPE_ANY:
316 return RTCNetworkAdapterType::kAny;
317 case rtc::ADAPTER_TYPE_VPN:
318 /* should not be handled here. Vpn is modelled as a bool */
319 break;
320 }
321 RTC_DCHECK_NOTREACHED();
Mirko Bonadei23e46542022-04-07 15:27:15322 return {};
Jonas Oreland0d13bbd2022-03-02 10:17:36323}
324
Henrik Boströmce33b6a2019-05-28 15:42:38325const char* QualityLimitationReasonToRTCQualityLimitationReason(
326 QualityLimitationReason reason) {
327 switch (reason) {
328 case QualityLimitationReason::kNone:
329 return RTCQualityLimitationReason::kNone;
330 case QualityLimitationReason::kCpu:
331 return RTCQualityLimitationReason::kCpu;
332 case QualityLimitationReason::kBandwidth:
333 return RTCQualityLimitationReason::kBandwidth;
334 case QualityLimitationReason::kOther:
335 return RTCQualityLimitationReason::kOther;
336 }
Karl Wibergc95b9392020-11-07 23:49:37337 RTC_CHECK_NOTREACHED();
Henrik Boströmce33b6a2019-05-28 15:42:38338}
339
Byoungchan Lee7d235352021-05-28 12:32:04340std::map<std::string, double>
341QualityLimitationDurationToRTCQualityLimitationDuration(
342 std::map<webrtc::QualityLimitationReason, int64_t> durations_ms) {
343 std::map<std::string, double> result;
Philipp Hancke3fd9cbc2022-01-10 16:41:43344 // The internal duration is defined in milliseconds while the spec defines
345 // the value in seconds:
346 // https://w3c.github.io/webrtc-stats/#dom-rtcoutboundrtpstreamstats-qualitylimitationdurations
Byoungchan Lee7d235352021-05-28 12:32:04347 for (const auto& elem : durations_ms) {
348 result[QualityLimitationReasonToRTCQualityLimitationReason(elem.first)] =
Philipp Hancke3fd9cbc2022-01-10 16:41:43349 elem.second / static_cast<double>(rtc::kNumMillisecsPerSec);
Byoungchan Lee7d235352021-05-28 12:32:04350 }
351 return result;
352}
353
hbos9e302742017-01-20 10:47:10354double DoubleAudioLevelFromIntAudioLevel(int audio_level) {
355 RTC_DCHECK_GE(audio_level, 0);
356 RTC_DCHECK_LE(audio_level, 32767);
357 return audio_level / 32767.0;
358}
359
Henrik Boström31c373b2022-09-26 12:56:21360// Gets the `codecId` identified by `transport_id` and `codec_params`. If no
361// such `RTCCodecStats` exist yet, create it and add it to `report`.
362std::string GetCodecIdAndMaybeCreateCodecStats(
Steve Anton57858b32018-02-15 23:19:50363 uint64_t timestamp_us,
Henrik Boström8dfc90f2022-09-02 07:39:29364 const char direction,
Philipp Hancke95157a02020-11-16 19:08:27365 const std::string& transport_id,
Henrik Boström31c373b2022-09-26 12:56:21366 const RtpCodecParameters& codec_params,
367 RTCStatsReport* report) {
hbos0adb8282016-11-23 10:32:06368 RTC_DCHECK_GE(codec_params.payload_type, 0);
369 RTC_DCHECK_LE(codec_params.payload_type, 127);
deadbeefe702b302017-02-04 20:09:01370 RTC_DCHECK(codec_params.clock_rate);
hbos0adb8282016-11-23 10:32:06371 uint32_t payload_type = static_cast<uint32_t>(codec_params.payload_type);
Henrik Boström31c373b2022-09-26 12:56:21372 std::string codec_id = RTCCodecStatsIDFromTransportAndCodecParameters(
373 direction, transport_id, codec_params);
374 if (report->Get(codec_id) != nullptr) {
375 // The `RTCCodecStats` already exists.
376 return codec_id;
377 }
378 // Create the `RTCCodecStats` that we want to reference.
379 std::unique_ptr<RTCCodecStats> codec_stats(
380 std::make_unique<RTCCodecStats>(codec_id, timestamp_us));
hbos0adb8282016-11-23 10:32:06381 codec_stats->payload_type = payload_type;
hbos13f54b22017-02-28 14:56:04382 codec_stats->mime_type = codec_params.mime_type();
Philipp Hancke42e5ed32022-11-02 15:08:16383 if (codec_params.clock_rate.has_value()) {
deadbeefe702b302017-02-04 20:09:01384 codec_stats->clock_rate = static_cast<uint32_t>(*codec_params.clock_rate);
385 }
Johannes Kron72d69152020-02-10 13:05:55386 if (codec_params.num_channels) {
387 codec_stats->channels = *codec_params.num_channels;
388 }
389
390 rtc::StringBuilder fmtp;
391 if (WriteFmtpParameters(codec_params.parameters, &fmtp)) {
392 codec_stats->sdp_fmtp_line = fmtp.Release();
393 }
Philipp Hancke95157a02020-11-16 19:08:27394 codec_stats->transport_id = transport_id;
Henrik Boström31c373b2022-09-26 12:56:21395 report->AddStats(std::move(codec_stats));
396 return codec_id;
hbos0adb8282016-11-23 10:32:06397}
398
hbos09bc1282016-11-08 14:29:22399void SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
400 const MediaStreamTrackInterface& track,
Henrik Boström15166b22022-10-19 09:06:58401 DEPRECATED_RTCMediaStreamTrackStats* track_stats) {
hbos09bc1282016-11-08 14:29:22402 track_stats->track_identifier = track.id();
403 track_stats->ended = (track.state() == MediaStreamTrackInterface::kEnded);
404}
405
hbos820f5782016-11-22 11:16:50406// Provides the media independent counters (both audio and video).
hboseeafe942016-11-01 10:00:17407void SetInboundRTPStreamStatsFromMediaReceiverInfo(
408 const cricket::MediaReceiverInfo& media_receiver_info,
409 RTCInboundRTPStreamStats* inbound_stats) {
410 RTC_DCHECK(inbound_stats);
hbos3443bb72017-02-07 14:28:11411 inbound_stats->ssrc = media_receiver_info.ssrc();
hboseeafe942016-11-01 10:00:17412 inbound_stats->packets_received =
413 static_cast<uint32_t>(media_receiver_info.packets_rcvd);
414 inbound_stats->bytes_received =
Niels Möllerac0a4cb2019-10-09 13:01:33415 static_cast<uint64_t>(media_receiver_info.payload_bytes_rcvd);
416 inbound_stats->header_bytes_received =
417 static_cast<uint64_t>(media_receiver_info.header_and_padding_bytes_rcvd);
hbos02cd4d62016-12-09 12:19:44418 inbound_stats->packets_lost =
Harald Alvestrand719487e2017-12-13 11:26:04419 static_cast<int32_t>(media_receiver_info.packets_lost);
Byoungchan Lee899b29e2021-06-29 13:09:18420 inbound_stats->jitter_buffer_delay =
421 media_receiver_info.jitter_buffer_delay_seconds;
Philipp Hancke42e5ed32022-11-02 15:08:16422 if (media_receiver_info.jitter_buffer_target_delay_seconds.has_value()) {
Ivo Creusen11fdb082022-07-04 12:16:39423 inbound_stats->jitter_buffer_target_delay =
424 *media_receiver_info.jitter_buffer_target_delay_seconds;
425 }
Philipp Hancke42e5ed32022-11-02 15:08:16426 if (media_receiver_info.jitter_buffer_minimum_delay_seconds.has_value()) {
Ivo Creusen1a84b562022-07-19 14:33:10427 inbound_stats->jitter_buffer_minimum_delay =
428 *media_receiver_info.jitter_buffer_minimum_delay_seconds;
429 }
Byoungchan Lee899b29e2021-06-29 13:09:18430 inbound_stats->jitter_buffer_emitted_count =
431 media_receiver_info.jitter_buffer_emitted_count;
Philipp Hancke42e5ed32022-11-02 15:08:16432 if (media_receiver_info.nacks_sent.has_value()) {
Jakob Ivarssone54914a2021-07-01 09:16:05433 inbound_stats->nack_count = *media_receiver_info.nacks_sent;
434 }
hboseeafe942016-11-01 10:00:17435}
436
Alessio Bazzicaf7b1b952021-03-23 16:23:04437std::unique_ptr<RTCInboundRTPStreamStats> CreateInboundAudioStreamStats(
Henrik Boströmb2be3922022-09-02 07:37:08438 const cricket::VoiceMediaInfo& voice_media_info,
hboseeafe942016-11-01 10:00:17439 const cricket::VoiceReceiverInfo& voice_receiver_info,
Henrik Boströmb2be3922022-09-02 07:37:08440 const std::string& transport_id,
Alessio Bazzicaf7b1b952021-03-23 16:23:04441 const std::string& mid,
Henrik Boström31c373b2022-09-26 12:56:21442 int64_t timestamp_us,
443 RTCStatsReport* report) {
Alessio Bazzicaf7b1b952021-03-23 16:23:04444 auto inbound_audio = std::make_unique<RTCInboundRTPStreamStats>(
Henrik Boströmb43e3bb2022-09-26 10:36:44445 /*id=*/RTCInboundRTPStreamStatsIDFromSSRC(
446 transport_id, cricket::MEDIA_TYPE_AUDIO, voice_receiver_info.ssrc()),
Alessio Bazzicaf7b1b952021-03-23 16:23:04447 timestamp_us);
Jonas Olssona4d87372019-07-05 17:08:33448 SetInboundRTPStreamStatsFromMediaReceiverInfo(voice_receiver_info,
Alessio Bazzicaf7b1b952021-03-23 16:23:04449 inbound_audio.get());
Henrik Boströmb2be3922022-09-02 07:37:08450 inbound_audio->transport_id = transport_id;
Henrik Boström1ab61882022-06-16 15:07:33451 inbound_audio->mid = mid;
hbos820f5782016-11-22 11:16:50452 inbound_audio->media_type = "audio";
Philipp Hancke3bc01662018-08-28 12:55:03453 inbound_audio->kind = "audio";
Henrik Boströmb2be3922022-09-02 07:37:08454 if (voice_receiver_info.codec_payload_type.has_value()) {
455 auto codec_param_it = voice_media_info.receive_codecs.find(
456 voice_receiver_info.codec_payload_type.value());
457 RTC_DCHECK(codec_param_it != voice_media_info.receive_codecs.end());
458 if (codec_param_it != voice_media_info.receive_codecs.end()) {
Henrik Boström31c373b2022-09-26 12:56:21459 inbound_audio->codec_id = GetCodecIdAndMaybeCreateCodecStats(
460 inbound_audio->timestamp_us(), kDirectionInbound, transport_id,
461 codec_param_it->second, report);
Henrik Boströmb2be3922022-09-02 07:37:08462 }
hbos585a9b12017-02-07 12:59:16463 }
Jonas Olssona4d87372019-07-05 17:08:33464 inbound_audio->jitter = static_cast<double>(voice_receiver_info.jitter_ms) /
465 rtc::kNumMillisecsPerSec;
Eldar Rello4e5bc9f2020-07-06 11:18:07466 inbound_audio->total_samples_received =
467 voice_receiver_info.total_samples_received;
468 inbound_audio->concealed_samples = voice_receiver_info.concealed_samples;
469 inbound_audio->silent_concealed_samples =
470 voice_receiver_info.silent_concealed_samples;
471 inbound_audio->concealment_events = voice_receiver_info.concealment_events;
472 inbound_audio->inserted_samples_for_deceleration =
473 voice_receiver_info.inserted_samples_for_deceleration;
474 inbound_audio->removed_samples_for_acceleration =
475 voice_receiver_info.removed_samples_for_acceleration;
Philipp Hanckeaa83cc72020-10-27 08:50:36476 if (voice_receiver_info.audio_level >= 0) {
477 inbound_audio->audio_level =
478 DoubleAudioLevelFromIntAudioLevel(voice_receiver_info.audio_level);
479 }
Eldar Rello4e5bc9f2020-07-06 11:18:07480 inbound_audio->total_audio_energy = voice_receiver_info.total_output_energy;
481 inbound_audio->total_samples_duration =
482 voice_receiver_info.total_output_duration;
Artem Titov880fa812021-07-30 20:30:23483 // `fir_count`, `pli_count` and `sli_count` are only valid for video and are
hbos820f5782016-11-22 11:16:50484 // purposefully left undefined for audio.
Philipp Hancke42e5ed32022-11-02 15:08:16485 if (voice_receiver_info.last_packet_received_timestamp_ms.has_value()) {
Alessio Bazzicac366d512021-03-22 14:36:53486 inbound_audio->last_packet_received_timestamp = static_cast<double>(
487 *voice_receiver_info.last_packet_received_timestamp_ms);
Henrik Boström01738c62019-04-15 15:32:00488 }
Philipp Hancke42e5ed32022-11-02 15:08:16489 if (voice_receiver_info.estimated_playout_ntp_timestamp_ms.has_value()) {
Alessio Bazzica5cf8c2c2021-03-24 07:51:26490 // TODO(bugs.webrtc.org/10529): Fix time origin.
Åsa Perssonfcf79cc2019-10-22 13:23:44491 inbound_audio->estimated_playout_timestamp = static_cast<double>(
492 *voice_receiver_info.estimated_playout_ntp_timestamp_ms);
493 }
Ivo Creusen8d8ffdb2019-04-30 07:45:21494 inbound_audio->fec_packets_received =
495 voice_receiver_info.fec_packets_received;
496 inbound_audio->fec_packets_discarded =
497 voice_receiver_info.fec_packets_discarded;
Minyue Li28a2c632021-07-07 13:53:38498 inbound_audio->packets_discarded = voice_receiver_info.packets_discarded;
Henrik Boström2fb83072022-10-06 11:37:11499 inbound_audio->jitter_buffer_flushes =
500 voice_receiver_info.jitter_buffer_flushes;
501 inbound_audio->delayed_packet_outage_samples =
502 voice_receiver_info.delayed_packet_outage_samples;
503 inbound_audio->relative_packet_arrival_delay =
504 voice_receiver_info.relative_packet_arrival_delay_seconds;
505 inbound_audio->interruption_count =
506 voice_receiver_info.interruption_count >= 0
507 ? voice_receiver_info.interruption_count
508 : 0;
509 inbound_audio->total_interruption_duration =
510 static_cast<double>(voice_receiver_info.total_interruption_duration_ms) /
511 rtc::kNumMillisecsPerSec;
Alessio Bazzicaf7b1b952021-03-23 16:23:04512 return inbound_audio;
513}
514
515std::unique_ptr<RTCRemoteOutboundRtpStreamStats>
516CreateRemoteOutboundAudioStreamStats(
517 const cricket::VoiceReceiverInfo& voice_receiver_info,
518 const std::string& mid,
Henrik Boströmb2be3922022-09-02 07:37:08519 const RTCInboundRTPStreamStats& inbound_audio_stats,
Alessio Bazzicaf7b1b952021-03-23 16:23:04520 const std::string& transport_id) {
521 if (!voice_receiver_info.last_sender_report_timestamp_ms.has_value()) {
522 // Cannot create `RTCRemoteOutboundRtpStreamStats` when the RTCP SR arrival
523 // timestamp is not available - i.e., until the first sender report is
524 // received.
525 return nullptr;
526 }
527 RTC_DCHECK_GT(voice_receiver_info.sender_reports_reports_count, 0);
528
529 // Create.
530 auto stats = std::make_unique<RTCRemoteOutboundRtpStreamStats>(
531 /*id=*/RTCRemoteOutboundRTPStreamStatsIDFromSSRC(
532 cricket::MEDIA_TYPE_AUDIO, voice_receiver_info.ssrc()),
533 /*timestamp_us=*/rtc::kNumMicrosecsPerMillisec *
534 voice_receiver_info.last_sender_report_timestamp_ms.value());
535
536 // Populate.
537 // - RTCRtpStreamStats.
538 stats->ssrc = voice_receiver_info.ssrc();
539 stats->kind = "audio";
540 stats->transport_id = transport_id;
Henrik Boströmb2be3922022-09-02 07:37:08541 if (inbound_audio_stats.codec_id.is_defined()) {
542 stats->codec_id = *inbound_audio_stats.codec_id;
543 }
Alessio Bazzicaf7b1b952021-03-23 16:23:04544 // - RTCSentRtpStreamStats.
545 stats->packets_sent = voice_receiver_info.sender_reports_packets_sent;
546 stats->bytes_sent = voice_receiver_info.sender_reports_bytes_sent;
547 // - RTCRemoteOutboundRtpStreamStats.
Henrik Boströmb2be3922022-09-02 07:37:08548 stats->local_id = inbound_audio_stats.id();
Alessio Bazzicaf7b1b952021-03-23 16:23:04549 RTC_DCHECK(
550 voice_receiver_info.last_sender_report_remote_timestamp_ms.has_value());
551 stats->remote_timestamp = static_cast<double>(
552 voice_receiver_info.last_sender_report_remote_timestamp_ms.value());
553 stats->reports_sent = voice_receiver_info.sender_reports_reports_count;
Philipp Hancke42e5ed32022-11-02 15:08:16554 if (voice_receiver_info.round_trip_time.has_value()) {
Ivo Creusen2562cf02021-09-03 14:51:22555 stats->round_trip_time =
556 voice_receiver_info.round_trip_time->seconds<double>();
557 }
558 stats->round_trip_time_measurements =
559 voice_receiver_info.round_trip_time_measurements;
560 stats->total_round_trip_time =
561 voice_receiver_info.total_round_trip_time.seconds<double>();
Alessio Bazzicaf7b1b952021-03-23 16:23:04562
563 return stats;
hboseeafe942016-11-01 10:00:17564}
565
566void SetInboundRTPStreamStatsFromVideoReceiverInfo(
Henrik Boströmb2be3922022-09-02 07:37:08567 const std::string& transport_id,
Steve Anton57858b32018-02-15 23:19:50568 const std::string& mid,
Henrik Boströmb2be3922022-09-02 07:37:08569 const cricket::VideoMediaInfo& video_media_info,
hboseeafe942016-11-01 10:00:17570 const cricket::VideoReceiverInfo& video_receiver_info,
Henrik Boström31c373b2022-09-26 12:56:21571 RTCInboundRTPStreamStats* inbound_video,
572 RTCStatsReport* report) {
Jonas Olssona4d87372019-07-05 17:08:33573 SetInboundRTPStreamStatsFromMediaReceiverInfo(video_receiver_info,
574 inbound_video);
Henrik Boströmb2be3922022-09-02 07:37:08575 inbound_video->transport_id = transport_id;
Henrik Boström1ab61882022-06-16 15:07:33576 inbound_video->mid = mid;
hbos820f5782016-11-22 11:16:50577 inbound_video->media_type = "video";
Philipp Hancke3bc01662018-08-28 12:55:03578 inbound_video->kind = "video";
Henrik Boströmb2be3922022-09-02 07:37:08579 if (video_receiver_info.codec_payload_type.has_value()) {
580 auto codec_param_it = video_media_info.receive_codecs.find(
581 video_receiver_info.codec_payload_type.value());
582 RTC_DCHECK(codec_param_it != video_media_info.receive_codecs.end());
583 if (codec_param_it != video_media_info.receive_codecs.end()) {
Henrik Boström31c373b2022-09-26 12:56:21584 inbound_video->codec_id = GetCodecIdAndMaybeCreateCodecStats(
585 inbound_video->timestamp_us(), kDirectionInbound, transport_id,
586 codec_param_it->second, report);
Henrik Boströmb2be3922022-09-02 07:37:08587 }
hbos585a9b12017-02-07 12:59:16588 }
Di Wu (RP Room Eng)8af6b492021-02-20 01:34:22589 inbound_video->jitter = static_cast<double>(video_receiver_info.jitter_ms) /
590 rtc::kNumMillisecsPerSec;
hbos820f5782016-11-22 11:16:50591 inbound_video->fir_count =
592 static_cast<uint32_t>(video_receiver_info.firs_sent);
593 inbound_video->pli_count =
594 static_cast<uint32_t>(video_receiver_info.plis_sent);
Eldar Rello4e5bc9f2020-07-06 11:18:07595 inbound_video->frames_received = video_receiver_info.frames_received;
hbos6769c492017-01-02 16:35:13596 inbound_video->frames_decoded = video_receiver_info.frames_decoded;
Eldar Rello4e5bc9f2020-07-06 11:18:07597 inbound_video->frames_dropped = video_receiver_info.frames_dropped;
Rasmus Brandt2efae772019-06-27 12:29:34598 inbound_video->key_frames_decoded = video_receiver_info.key_frames_decoded;
Eldar Rello4e5bc9f2020-07-06 11:18:07599 if (video_receiver_info.frame_width > 0) {
600 inbound_video->frame_width =
601 static_cast<uint32_t>(video_receiver_info.frame_width);
602 }
603 if (video_receiver_info.frame_height > 0) {
604 inbound_video->frame_height =
605 static_cast<uint32_t>(video_receiver_info.frame_height);
606 }
Philipp Hancke3719a0c2022-07-04 16:24:46607 if (video_receiver_info.framerate_decoded > 0) {
608 inbound_video->frames_per_second = video_receiver_info.framerate_decoded;
Eldar Rello4e5bc9f2020-07-06 11:18:07609 }
Philipp Hancke42e5ed32022-11-02 15:08:16610 if (video_receiver_info.qp_sum.has_value()) {
hbosa51d4f32017-02-16 13:34:48611 inbound_video->qp_sum = *video_receiver_info.qp_sum;
Henrik Boströmc5f8f802022-10-19 15:50:09612 }
613 if (video_receiver_info.timing_frame_info.has_value()) {
614 inbound_video->goog_timing_frame_info =
615 video_receiver_info.timing_frame_info->ToString();
616 }
Johannes Kronbfd343b2019-07-01 08:07:50617 inbound_video->total_decode_time =
Philipp Hanckea204ad22022-07-08 16:43:25618 video_receiver_info.total_decode_time.seconds<double>();
Philipp Hanckea16a6a62022-04-25 10:21:30619 inbound_video->total_processing_delay =
Philipp Hanckea204ad22022-07-08 16:43:25620 video_receiver_info.total_processing_delay.seconds<double>();
Philipp Hancke0359ba22022-05-05 13:55:36621 inbound_video->total_assembly_time =
Philipp Hanckea204ad22022-07-08 16:43:25622 video_receiver_info.total_assembly_time.seconds<double>();
Philipp Hancke0359ba22022-05-05 13:55:36623 inbound_video->frames_assembled_from_multiple_packets =
624 video_receiver_info.frames_assembled_from_multiple_packets;
Johannes Kron00376e12019-11-25 09:25:42625 inbound_video->total_inter_frame_delay =
626 video_receiver_info.total_inter_frame_delay;
627 inbound_video->total_squared_inter_frame_delay =
628 video_receiver_info.total_squared_inter_frame_delay;
Henrik Boströmc57a28c2022-10-06 09:59:05629 inbound_video->pause_count = video_receiver_info.pause_count;
630 inbound_video->total_pauses_duration =
631 static_cast<double>(video_receiver_info.total_pauses_duration_ms) /
632 rtc::kNumMillisecsPerSec;
633 inbound_video->freeze_count = video_receiver_info.freeze_count;
634 inbound_video->total_freezes_duration =
635 static_cast<double>(video_receiver_info.total_freezes_duration_ms) /
636 rtc::kNumMillisecsPerSec;
Philipp Hancke6fb8d1a2022-05-30 10:37:04637 inbound_video->min_playout_delay =
638 static_cast<double>(video_receiver_info.min_playout_delay_ms) /
639 rtc::kNumMillisecsPerSec;
Philipp Hancke42e5ed32022-11-02 15:08:16640 if (video_receiver_info.last_packet_received_timestamp_ms.has_value()) {
Alessio Bazzica5cf8c2c2021-03-24 07:51:26641 inbound_video->last_packet_received_timestamp = static_cast<double>(
642 *video_receiver_info.last_packet_received_timestamp_ms);
Henrik Boström01738c62019-04-15 15:32:00643 }
Philipp Hancke42e5ed32022-11-02 15:08:16644 if (video_receiver_info.estimated_playout_ntp_timestamp_ms.has_value()) {
Alessio Bazzica5cf8c2c2021-03-24 07:51:26645 // TODO(bugs.webrtc.org/10529): Fix time origin if needed.
Åsa Perssonfcf79cc2019-10-22 13:23:44646 inbound_video->estimated_playout_timestamp = static_cast<double>(
647 *video_receiver_info.estimated_playout_ntp_timestamp_ms);
648 }
Artem Titov880fa812021-07-30 20:30:23649 // TODO(bugs.webrtc.org/10529): When info's `content_info` is optional
Alessio Bazzica5cf8c2c2021-03-24 07:51:26650 // support the "unspecified" value.
Henrik Boström2e069262019-04-09 11:59:31651 if (video_receiver_info.content_type == VideoContentType::SCREENSHARE)
652 inbound_video->content_type = RTCContentType::kScreenshare;
Henrik Boström6b430862019-08-16 11:09:51653 if (!video_receiver_info.decoder_implementation_name.empty()) {
654 inbound_video->decoder_implementation =
655 video_receiver_info.decoder_implementation_name;
656 }
Evan Shrubsole13c0be42022-10-31 11:03:10657 if (video_receiver_info.power_efficient_decoder.has_value()) {
658 inbound_video->power_efficient_decoder =
659 video_receiver_info.power_efficient_decoder.value();
660 }
hboseeafe942016-11-01 10:00:17661}
662
Philipp Hancke684e2412022-07-28 10:41:00663// Provides the media independent counters and information (both audio and
664// video).
hbos6ded1902016-11-01 08:50:46665void SetOutboundRTPStreamStatsFromMediaSenderInfo(
666 const cricket::MediaSenderInfo& media_sender_info,
667 RTCOutboundRTPStreamStats* outbound_stats) {
668 RTC_DCHECK(outbound_stats);
hbos3443bb72017-02-07 14:28:11669 outbound_stats->ssrc = media_sender_info.ssrc();
hbos6ded1902016-11-01 08:50:46670 outbound_stats->packets_sent =
671 static_cast<uint32_t>(media_sender_info.packets_sent);
Henrik Boströmaebba7b2022-10-26 14:53:03672 outbound_stats->total_packet_send_delay =
673 media_sender_info.total_packet_send_delay.seconds<double>();
Henrik Boströmcf96e0f2019-04-17 11:51:53674 outbound_stats->retransmitted_packets_sent =
675 media_sender_info.retransmitted_packets_sent;
hbos6ded1902016-11-01 08:50:46676 outbound_stats->bytes_sent =
Niels Möllerac0a4cb2019-10-09 13:01:33677 static_cast<uint64_t>(media_sender_info.payload_bytes_sent);
678 outbound_stats->header_bytes_sent =
679 static_cast<uint64_t>(media_sender_info.header_and_padding_bytes_sent);
Henrik Boströmcf96e0f2019-04-17 11:51:53680 outbound_stats->retransmitted_bytes_sent =
681 media_sender_info.retransmitted_bytes_sent;
Jakob Ivarssone91c9922021-07-06 07:55:43682 outbound_stats->nack_count = media_sender_info.nacks_rcvd;
Philipp Hancke684e2412022-07-28 10:41:00683 if (media_sender_info.active.has_value()) {
684 outbound_stats->active = *media_sender_info.active;
685 }
hbos6ded1902016-11-01 08:50:46686}
687
688void SetOutboundRTPStreamStatsFromVoiceSenderInfo(
Henrik Boströmb2be3922022-09-02 07:37:08689 const std::string& transport_id,
Steve Anton57858b32018-02-15 23:19:50690 const std::string& mid,
Henrik Boströmb2be3922022-09-02 07:37:08691 const cricket::VoiceMediaInfo& voice_media_info,
hbos6ded1902016-11-01 08:50:46692 const cricket::VoiceSenderInfo& voice_sender_info,
Henrik Boström31c373b2022-09-26 12:56:21693 RTCOutboundRTPStreamStats* outbound_audio,
694 RTCStatsReport* report) {
Jonas Olssona4d87372019-07-05 17:08:33695 SetOutboundRTPStreamStatsFromMediaSenderInfo(voice_sender_info,
696 outbound_audio);
Henrik Boströmb2be3922022-09-02 07:37:08697 outbound_audio->transport_id = transport_id;
Henrik Boström1ab61882022-06-16 15:07:33698 outbound_audio->mid = mid;
hbos6ded1902016-11-01 08:50:46699 outbound_audio->media_type = "audio";
Philipp Hancke3bc01662018-08-28 12:55:03700 outbound_audio->kind = "audio";
Philipp Hancke42e5ed32022-11-02 15:08:16701 if (voice_sender_info.target_bitrate.has_value() &&
Byoungchan Lee636dc3d2022-09-22 10:50:00702 *voice_sender_info.target_bitrate > 0) {
703 outbound_audio->target_bitrate = *voice_sender_info.target_bitrate;
Jakob Ivarssonbf087452021-11-11 12:43:49704 }
Henrik Boströmb2be3922022-09-02 07:37:08705 if (voice_sender_info.codec_payload_type.has_value()) {
706 auto codec_param_it = voice_media_info.send_codecs.find(
707 voice_sender_info.codec_payload_type.value());
708 RTC_DCHECK(codec_param_it != voice_media_info.send_codecs.end());
709 if (codec_param_it != voice_media_info.send_codecs.end()) {
Henrik Boström31c373b2022-09-26 12:56:21710 outbound_audio->codec_id = GetCodecIdAndMaybeCreateCodecStats(
711 outbound_audio->timestamp_us(), kDirectionOutbound, transport_id,
712 codec_param_it->second, report);
Henrik Boströmb2be3922022-09-02 07:37:08713 }
hbos585a9b12017-02-07 12:59:16714 }
Artem Titov880fa812021-07-30 20:30:23715 // `fir_count`, `pli_count` and `sli_count` are only valid for video and are
hbos6ded1902016-11-01 08:50:46716 // purposefully left undefined for audio.
717}
718
719void SetOutboundRTPStreamStatsFromVideoSenderInfo(
Henrik Boströmb2be3922022-09-02 07:37:08720 const std::string& transport_id,
Steve Anton57858b32018-02-15 23:19:50721 const std::string& mid,
Henrik Boströmb2be3922022-09-02 07:37:08722 const cricket::VideoMediaInfo& video_media_info,
hbos6ded1902016-11-01 08:50:46723 const cricket::VideoSenderInfo& video_sender_info,
Henrik Boström31c373b2022-09-26 12:56:21724 RTCOutboundRTPStreamStats* outbound_video,
725 RTCStatsReport* report) {
Jonas Olssona4d87372019-07-05 17:08:33726 SetOutboundRTPStreamStatsFromMediaSenderInfo(video_sender_info,
727 outbound_video);
Henrik Boströmb2be3922022-09-02 07:37:08728 outbound_video->transport_id = transport_id;
Henrik Boström1ab61882022-06-16 15:07:33729 outbound_video->mid = mid;
hbos6ded1902016-11-01 08:50:46730 outbound_video->media_type = "video";
Philipp Hancke3bc01662018-08-28 12:55:03731 outbound_video->kind = "video";
Henrik Boströmb2be3922022-09-02 07:37:08732 if (video_sender_info.codec_payload_type.has_value()) {
733 auto codec_param_it = video_media_info.send_codecs.find(
734 video_sender_info.codec_payload_type.value());
735 RTC_DCHECK(codec_param_it != video_media_info.send_codecs.end());
736 if (codec_param_it != video_media_info.send_codecs.end()) {
Henrik Boström31c373b2022-09-26 12:56:21737 outbound_video->codec_id = GetCodecIdAndMaybeCreateCodecStats(
738 outbound_video->timestamp_us(), kDirectionOutbound, transport_id,
739 codec_param_it->second, report);
Henrik Boströmb2be3922022-09-02 07:37:08740 }
hbos585a9b12017-02-07 12:59:16741 }
hbos6ded1902016-11-01 08:50:46742 outbound_video->fir_count =
743 static_cast<uint32_t>(video_sender_info.firs_rcvd);
744 outbound_video->pli_count =
745 static_cast<uint32_t>(video_sender_info.plis_rcvd);
Philipp Hancke42e5ed32022-11-02 15:08:16746 if (video_sender_info.qp_sum.has_value())
hbos6769c492017-01-02 16:35:13747 outbound_video->qp_sum = *video_sender_info.qp_sum;
Philipp Hancke42e5ed32022-11-02 15:08:16748 if (video_sender_info.target_bitrate.has_value() &&
749 *video_sender_info.target_bitrate > 0) {
Byoungchan Lee636dc3d2022-09-22 10:50:00750 outbound_video->target_bitrate = *video_sender_info.target_bitrate;
751 }
hbos6769c492017-01-02 16:35:13752 outbound_video->frames_encoded = video_sender_info.frames_encoded;
Rasmus Brandt2efae772019-06-27 12:29:34753 outbound_video->key_frames_encoded = video_sender_info.key_frames_encoded;
Henrik Boströmf71362f2019-04-08 14:14:23754 outbound_video->total_encode_time =
755 static_cast<double>(video_sender_info.total_encode_time_ms) /
756 rtc::kNumMillisecsPerSec;
Henrik Boström23aff9b2019-05-20 13:15:38757 outbound_video->total_encoded_bytes_target =
758 video_sender_info.total_encoded_bytes_target;
Eldar Rello9276e2c2020-06-10 14:53:39759 if (video_sender_info.send_frame_width > 0) {
760 outbound_video->frame_width =
761 static_cast<uint32_t>(video_sender_info.send_frame_width);
Henrik Boströma0ff50c2020-05-05 13:54:46762 }
Eldar Rello9276e2c2020-06-10 14:53:39763 if (video_sender_info.send_frame_height > 0) {
764 outbound_video->frame_height =
765 static_cast<uint32_t>(video_sender_info.send_frame_height);
766 }
767 if (video_sender_info.framerate_sent > 0) {
768 outbound_video->frames_per_second = video_sender_info.framerate_sent;
769 }
770 outbound_video->frames_sent = video_sender_info.frames_sent;
771 outbound_video->huge_frames_sent = video_sender_info.huge_frames_sent;
Henrik Boströmce33b6a2019-05-28 15:42:38772 outbound_video->quality_limitation_reason =
773 QualityLimitationReasonToRTCQualityLimitationReason(
774 video_sender_info.quality_limitation_reason);
Byoungchan Lee7d235352021-05-28 12:32:04775 outbound_video->quality_limitation_durations =
776 QualityLimitationDurationToRTCQualityLimitationDuration(
777 video_sender_info.quality_limitation_durations_ms);
Evan Shrubsolecc62b162019-09-09 09:26:45778 outbound_video->quality_limitation_resolution_changes =
779 video_sender_info.quality_limitation_resolution_changes;
Artem Titov880fa812021-07-30 20:30:23780 // TODO(https://crbug.com/webrtc/10529): When info's `content_info` is
Henrik Boström2e069262019-04-09 11:59:31781 // optional, support the "unspecified" value.
782 if (video_sender_info.content_type == VideoContentType::SCREENSHARE)
783 outbound_video->content_type = RTCContentType::kScreenshare;
Henrik Boström6b430862019-08-16 11:09:51784 if (!video_sender_info.encoder_implementation_name.empty()) {
785 outbound_video->encoder_implementation =
786 video_sender_info.encoder_implementation_name;
787 }
Philipp Hancke42e5ed32022-11-02 15:08:16788 if (video_sender_info.rid.has_value()) {
Henrik Boströma0ff50c2020-05-05 13:54:46789 outbound_video->rid = *video_sender_info.rid;
790 }
Evan Shrubsole13c0be42022-10-31 11:03:10791 if (video_sender_info.power_efficient_encoder.has_value()) {
792 outbound_video->power_efficient_encoder =
793 video_sender_info.power_efficient_encoder.value();
794 }
hbos6ded1902016-11-01 08:50:46795}
796
Henrik Boström883eefc2019-05-27 11:40:25797std::unique_ptr<RTCRemoteInboundRtpStreamStats>
798ProduceRemoteInboundRtpStreamStatsFromReportBlockData(
Henrik Boströmb43e3bb2022-09-26 10:36:44799 const std::string& transport_id,
Henrik Boström883eefc2019-05-27 11:40:25800 const ReportBlockData& report_block_data,
801 cricket::MediaType media_type,
Eldar Relloc07e9042020-07-03 08:08:07802 const std::map<std::string, RTCOutboundRTPStreamStats*>& outbound_rtps,
Henrik Boström883eefc2019-05-27 11:40:25803 const RTCStatsReport& report) {
804 const auto& report_block = report_block_data.report_block();
805 // RTCStats' timestamp generally refers to when the metric was sampled, but
806 // for "remote-[outbound/inbound]-rtp" it refers to the local time when the
807 // Report Block was received.
Mirko Bonadei317a1f02019-09-17 15:06:18808 auto remote_inbound = std::make_unique<RTCRemoteInboundRtpStreamStats>(
Henrik Boström8605fbf2019-06-24 14:44:51809 RTCRemoteInboundRtpStreamStatsIdFromSourceSsrc(media_type,
810 report_block.source_ssrc),
Henrik Boström883eefc2019-05-27 11:40:25811 /*timestamp=*/report_block_data.report_block_timestamp_utc_us());
Henrik Boström8605fbf2019-06-24 14:44:51812 remote_inbound->ssrc = report_block.source_ssrc;
Henrik Boström883eefc2019-05-27 11:40:25813 remote_inbound->kind =
814 media_type == cricket::MEDIA_TYPE_AUDIO ? "audio" : "video";
815 remote_inbound->packets_lost = report_block.packets_lost;
Di Wu86f04ad2021-03-01 07:36:03816 remote_inbound->fraction_lost =
817 static_cast<double>(report_block.fraction_lost) / (1 << 8);
Henrik Boströma3a3b6d2022-11-22 08:56:49818 if (report_block_data.num_rtts() > 0) {
819 remote_inbound->round_trip_time =
820 static_cast<double>(report_block_data.last_rtt_ms()) /
821 rtc::kNumMillisecsPerSec;
822 }
Di Wu88a51b22021-03-01 19:22:06823 remote_inbound->total_round_trip_time =
824 static_cast<double>(report_block_data.sum_rtt_ms()) /
825 rtc::kNumMillisecsPerSec;
826 remote_inbound->round_trip_time_measurements =
827 report_block_data.num_rtts();
Henrik Boström883eefc2019-05-27 11:40:25828
Henrik Boströmb43e3bb2022-09-26 10:36:44829 std::string local_id = RTCOutboundRTPStreamStatsIDFromSSRC(
830 transport_id, media_type, report_block.source_ssrc);
Artem Titov880fa812021-07-30 20:30:23831 // Look up local stat from `outbound_rtps` where the pointers are non-const.
Henrik Boström4f40fa52019-12-19 12:27:27832 auto local_id_it = outbound_rtps.find(local_id);
833 if (local_id_it != outbound_rtps.end()) {
Henrik Boström883eefc2019-05-27 11:40:25834 remote_inbound->local_id = local_id;
Henrik Boström4f40fa52019-12-19 12:27:27835 auto& outbound_rtp = *local_id_it->second;
836 outbound_rtp.remote_id = remote_inbound->id();
Henrik Boström883eefc2019-05-27 11:40:25837 // The RTP/RTCP transport is obtained from the
838 // RTCOutboundRtpStreamStats's transport.
Henrik Boströmb43e3bb2022-09-26 10:36:44839 const auto* transport_from_id = report.Get(transport_id);
Henrik Boström883eefc2019-05-27 11:40:25840 if (transport_from_id) {
841 const auto& transport = transport_from_id->cast_to<RTCTransportStats>();
842 // If RTP and RTCP are not multiplexed, there is a separate RTCP
843 // transport paired with the RTP transport, otherwise the same
844 // transport is used for RTCP and RTP.
845 remote_inbound->transport_id =
846 transport.rtcp_transport_stats_id.is_defined()
847 ? *transport.rtcp_transport_stats_id
848 : *outbound_rtp.transport_id;
849 }
850 // We're assuming the same codec is used on both ends. However if the
851 // codec is switched out on the fly we may have received a Report Block
852 // based on the previous codec and there is no way to tell which point in
853 // time the codec changed for the remote end.
854 const auto* codec_from_id = outbound_rtp.codec_id.is_defined()
855 ? report.Get(*outbound_rtp.codec_id)
856 : nullptr;
857 if (codec_from_id) {
858 remote_inbound->codec_id = *outbound_rtp.codec_id;
859 const auto& codec = codec_from_id->cast_to<RTCCodecStats>();
860 if (codec.clock_rate.is_defined()) {
861 // The Report Block jitter is expressed in RTP timestamp units
862 // (https://tools.ietf.org/html/rfc3550#section-6.4.1). To convert this
863 // to seconds we divide by the codec's clock rate.
864 remote_inbound->jitter =
865 static_cast<double>(report_block.jitter) / *codec.clock_rate;
866 }
867 }
868 }
869 return remote_inbound;
870}
871
hbos02ba2112016-10-28 12:14:53872void ProduceCertificateStatsFromSSLCertificateStats(
Jonas Olssona4d87372019-07-05 17:08:33873 int64_t timestamp_us,
874 const rtc::SSLCertificateStats& certificate_stats,
hbos02ba2112016-10-28 12:14:53875 RTCStatsReport* report) {
876 RTCCertificateStats* prev_certificate_stats = nullptr;
877 for (const rtc::SSLCertificateStats* s = &certificate_stats; s;
878 s = s->issuer.get()) {
hbos02d2a922016-12-21 09:29:05879 std::string certificate_stats_id =
880 RTCCertificateIDFromFingerprint(s->fingerprint);
881 // It is possible for the same certificate to show up multiple times, e.g.
882 // if local and remote side use the same certificate in a loopback call.
883 // If the report already contains stats for this certificate, skip it.
884 if (report->Get(certificate_stats_id)) {
885 RTC_DCHECK_EQ(s, &certificate_stats);
886 break;
887 }
Jonas Olssona4d87372019-07-05 17:08:33888 RTCCertificateStats* certificate_stats =
889 new RTCCertificateStats(certificate_stats_id, timestamp_us);
hbos02ba2112016-10-28 12:14:53890 certificate_stats->fingerprint = s->fingerprint;
891 certificate_stats->fingerprint_algorithm = s->fingerprint_algorithm;
892 certificate_stats->base64_certificate = s->base64_certificate;
893 if (prev_certificate_stats)
894 prev_certificate_stats->issuer_certificate_id = certificate_stats->id();
895 report->AddStats(std::unique_ptr<RTCCertificateStats>(certificate_stats));
896 prev_certificate_stats = certificate_stats;
897 }
898}
899
Jonas Olssona4d87372019-07-05 17:08:33900const std::string& ProduceIceCandidateStats(int64_t timestamp_us,
901 const cricket::Candidate& candidate,
902 bool is_local,
903 const std::string& transport_id,
904 RTCStatsReport* report) {
Henrik Boström8dfc90f2022-09-02 07:39:29905 const std::string& id = "I" + candidate.id();
hbos02ba2112016-10-28 12:14:53906 const RTCStats* stats = report->Get(id);
907 if (!stats) {
908 std::unique_ptr<RTCIceCandidateStats> candidate_stats;
909 if (is_local)
Philipp Hanckeb5cf12d2022-09-06 09:55:31910 candidate_stats =
911 std::make_unique<RTCLocalIceCandidateStats>(id, timestamp_us);
hbos02ba2112016-10-28 12:14:53912 else
Philipp Hanckeb5cf12d2022-09-06 09:55:31913 candidate_stats =
914 std::make_unique<RTCRemoteIceCandidateStats>(id, timestamp_us);
hbosb4e426e2017-01-02 17:59:31915 candidate_stats->transport_id = transport_id;
Gary Liu37e489c2017-11-21 18:49:36916 if (is_local) {
917 candidate_stats->network_type =
Jonas Oreland0d13bbd2022-03-02 10:17:36918 NetworkTypeToStatsType(candidate.network_type());
Philipp Hancke21c4b1e2021-11-11 06:45:59919 const std::string& candidate_type = candidate.type();
920 const std::string& relay_protocol = candidate.relay_protocol();
Philipp Hancke05b29c72022-02-02 11:06:15921 const std::string& url = candidate.url();
Philipp Hancke21c4b1e2021-11-11 06:45:59922 if (candidate_type == cricket::RELAY_PORT_TYPE ||
923 (candidate_type == cricket::PRFLX_PORT_TYPE &&
924 !relay_protocol.empty())) {
Philipp Hancke95513752018-09-27 12:40:08925 RTC_DCHECK(relay_protocol.compare("udp") == 0 ||
926 relay_protocol.compare("tcp") == 0 ||
927 relay_protocol.compare("tls") == 0);
928 candidate_stats->relay_protocol = relay_protocol;
Philipp Hancke05b29c72022-02-02 11:06:15929 if (!url.empty()) {
930 candidate_stats->url = url;
931 }
932 } else if (candidate_type == cricket::STUN_PORT_TYPE) {
933 if (!url.empty()) {
934 candidate_stats->url = url;
935 }
Philipp Hancke95513752018-09-27 12:40:08936 }
Jonas Oreland0d13bbd2022-03-02 10:17:36937 if (candidate.network_type() == rtc::ADAPTER_TYPE_VPN) {
938 candidate_stats->vpn = true;
939 candidate_stats->network_adapter_type =
940 std::string(NetworkTypeToStatsNetworkAdapterType(
941 candidate.underlying_type_for_vpn()));
942 } else {
943 candidate_stats->vpn = false;
944 candidate_stats->network_adapter_type = std::string(
945 NetworkTypeToStatsNetworkAdapterType(candidate.network_type()));
946 }
Gary Liu37e489c2017-11-21 18:49:36947 } else {
948 // We don't expect to know the adapter type of remote candidates.
949 RTC_DCHECK_EQ(rtc::ADAPTER_TYPE_UNKNOWN, candidate.network_type());
Byoungchan Lee5a925772022-10-18 17:43:18950 RTC_DCHECK_EQ(0, candidate.relay_protocol().compare(""));
951 RTC_DCHECK_EQ(rtc::ADAPTER_TYPE_UNKNOWN,
952 candidate.underlying_type_for_vpn());
Gary Liu37e489c2017-11-21 18:49:36953 }
hbos02ba2112016-10-28 12:14:53954 candidate_stats->ip = candidate.address().ipaddr().ToString();
Philipp Hanckea9ba4502021-03-22 12:22:54955 candidate_stats->address = candidate.address().ipaddr().ToString();
hbos02ba2112016-10-28 12:14:53956 candidate_stats->port = static_cast<int32_t>(candidate.address().port());
957 candidate_stats->protocol = candidate.protocol();
Jonas Olssona4d87372019-07-05 17:08:33958 candidate_stats->candidate_type =
959 CandidateTypeToRTCIceCandidateType(candidate.type());
hbos02ba2112016-10-28 12:14:53960 candidate_stats->priority = static_cast<int32_t>(candidate.priority());
Philipp Hancke0e3cd632022-09-27 08:23:09961 candidate_stats->foundation = candidate.foundation();
962 auto related_address = candidate.related_address();
963 if (related_address.port() != 0) {
964 candidate_stats->related_address = related_address.ipaddr().ToString();
965 candidate_stats->related_port =
966 static_cast<int32_t>(related_address.port());
967 }
968 candidate_stats->username_fragment = candidate.username();
969 if (candidate.protocol() == "tcp") {
970 candidate_stats->tcp_type = candidate.tcptype();
971 }
hbos02ba2112016-10-28 12:14:53972
973 stats = candidate_stats.get();
974 report->AddStats(std::move(candidate_stats));
975 }
976 RTC_DCHECK_EQ(stats->type(), is_local ? RTCLocalIceCandidateStats::kType
977 : RTCRemoteIceCandidateStats::kType);
978 return stats->id();
979}
980
Taylor Brandstetter64851c02021-06-24 20:32:50981template <typename StatsType>
982void SetAudioProcessingStats(StatsType* stats,
983 const AudioProcessingStats& apm_stats) {
Philipp Hancke42e5ed32022-11-02 15:08:16984 if (apm_stats.echo_return_loss.has_value()) {
Taylor Brandstetter64851c02021-06-24 20:32:50985 stats->echo_return_loss = *apm_stats.echo_return_loss;
986 }
Philipp Hancke42e5ed32022-11-02 15:08:16987 if (apm_stats.echo_return_loss_enhancement.has_value()) {
Taylor Brandstetter64851c02021-06-24 20:32:50988 stats->echo_return_loss_enhancement =
989 *apm_stats.echo_return_loss_enhancement;
990 }
991}
992
Henrik Boström15166b22022-10-19 09:06:58993std::unique_ptr<DEPRECATED_RTCMediaStreamTrackStats>
hbos9e302742017-01-20 10:47:10994ProduceMediaStreamTrackStatsFromVoiceSenderInfo(
995 int64_t timestamp_us,
Taylor Brandstetter64851c02021-06-24 20:32:50996 AudioTrackInterface& audio_track,
Harald Alvestrandc72af932018-01-11 16:18:19997 const cricket::VoiceSenderInfo& voice_sender_info,
998 int attachment_id) {
Henrik Boström15166b22022-10-19 09:06:58999 std::unique_ptr<DEPRECATED_RTCMediaStreamTrackStats> audio_track_stats(
1000 std::make_unique<DEPRECATED_RTCMediaStreamTrackStats>(
1001 DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
Henrik Boström8dfc90f2022-09-02 07:39:291002 kDirectionOutbound, attachment_id),
Harald Alvestrandc72af932018-01-11 16:18:191003 timestamp_us, RTCMediaStreamTrackKind::kAudio));
hbos9e302742017-01-20 10:47:101004 SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
1005 audio_track, audio_track_stats.get());
Henrik Boström646fda02019-05-22 13:49:421006 audio_track_stats->media_source_id =
1007 RTCMediaSourceStatsIDFromKindAndAttachment(cricket::MEDIA_TYPE_AUDIO,
1008 attachment_id);
hbos9e302742017-01-20 10:47:101009 audio_track_stats->remote_source = false;
1010 audio_track_stats->detached = false;
Taylor Brandstetter64851c02021-06-24 20:32:501011 // Audio processor may be attached to either the track or the send
1012 // stream, so look in both places.
1013 SetAudioProcessingStats(audio_track_stats.get(),
1014 voice_sender_info.apm_statistics);
1015 auto audio_processor(audio_track.GetAudioProcessor());
1016 if (audio_processor.get()) {
Artem Titov880fa812021-07-30 20:30:231017 // The `has_remote_tracks` argument is obsolete; makes no difference if it's
Taylor Brandstetter64851c02021-06-24 20:32:501018 // set to true or false.
1019 AudioProcessorInterface::AudioProcessorStatistics ap_stats =
1020 audio_processor->GetStats(/*has_remote_tracks=*/false);
1021 SetAudioProcessingStats(audio_track_stats.get(), ap_stats.apm_statistics);
hbos9e302742017-01-20 10:47:101022 }
1023 return audio_track_stats;
1024}
1025
Henrik Boström15166b22022-10-19 09:06:581026std::unique_ptr<DEPRECATED_RTCMediaStreamTrackStats>
hbos9e302742017-01-20 10:47:101027ProduceMediaStreamTrackStatsFromVoiceReceiverInfo(
1028 int64_t timestamp_us,
1029 const AudioTrackInterface& audio_track,
Harald Alvestrandc72af932018-01-11 16:18:191030 const cricket::VoiceReceiverInfo& voice_receiver_info,
1031 int attachment_id) {
1032 // Since receiver tracks can't be reattached, we use the SSRC as
1033 // an attachment identifier.
Henrik Boström15166b22022-10-19 09:06:581034 std::unique_ptr<DEPRECATED_RTCMediaStreamTrackStats> audio_track_stats(
1035 std::make_unique<DEPRECATED_RTCMediaStreamTrackStats>(
1036 DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
Henrik Boström8dfc90f2022-09-02 07:39:291037 kDirectionInbound, attachment_id),
Harald Alvestrandc72af932018-01-11 16:18:191038 timestamp_us, RTCMediaStreamTrackKind::kAudio));
hbos9e302742017-01-20 10:47:101039 SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
1040 audio_track, audio_track_stats.get());
1041 audio_track_stats->remote_source = true;
1042 audio_track_stats->detached = false;
1043 if (voice_receiver_info.audio_level >= 0) {
Jonas Olssona4d87372019-07-05 17:08:331044 audio_track_stats->audio_level =
1045 DoubleAudioLevelFromIntAudioLevel(voice_receiver_info.audio_level);
hbos9e302742017-01-20 10:47:101046 }
Gustaf Ullbergb0a02072017-10-02 10:00:341047 audio_track_stats->jitter_buffer_delay =
1048 voice_receiver_info.jitter_buffer_delay_seconds;
Chen Xing0acffb52019-01-15 14:46:291049 audio_track_stats->jitter_buffer_emitted_count =
1050 voice_receiver_info.jitter_buffer_emitted_count;
Ivo Creusen8d8ffdb2019-04-30 07:45:211051 audio_track_stats->inserted_samples_for_deceleration =
1052 voice_receiver_info.inserted_samples_for_deceleration;
1053 audio_track_stats->removed_samples_for_acceleration =
1054 voice_receiver_info.removed_samples_for_acceleration;
zsteine76bd3a2017-07-14 19:17:491055 audio_track_stats->total_audio_energy =
1056 voice_receiver_info.total_output_energy;
Steve Anton2dbc69f2017-08-25 00:15:131057 audio_track_stats->total_samples_received =
1058 voice_receiver_info.total_samples_received;
zsteine76bd3a2017-07-14 19:17:491059 audio_track_stats->total_samples_duration =
1060 voice_receiver_info.total_output_duration;
Steve Anton2dbc69f2017-08-25 00:15:131061 audio_track_stats->concealed_samples = voice_receiver_info.concealed_samples;
Ivo Creusen8d8ffdb2019-04-30 07:45:211062 audio_track_stats->silent_concealed_samples =
1063 voice_receiver_info.silent_concealed_samples;
Gustaf Ullberg9a2e9062017-09-18 07:28:201064 audio_track_stats->concealment_events =
1065 voice_receiver_info.concealment_events;
Henrik Boström2fb83072022-10-06 11:37:111066
hbos9e302742017-01-20 10:47:101067 return audio_track_stats;
1068}
1069
Henrik Boström15166b22022-10-19 09:06:581070std::unique_ptr<DEPRECATED_RTCMediaStreamTrackStats>
hbos9e302742017-01-20 10:47:101071ProduceMediaStreamTrackStatsFromVideoSenderInfo(
1072 int64_t timestamp_us,
1073 const VideoTrackInterface& video_track,
Harald Alvestrandc72af932018-01-11 16:18:191074 const cricket::VideoSenderInfo& video_sender_info,
1075 int attachment_id) {
Henrik Boström15166b22022-10-19 09:06:581076 std::unique_ptr<DEPRECATED_RTCMediaStreamTrackStats> video_track_stats(
1077 std::make_unique<DEPRECATED_RTCMediaStreamTrackStats>(
1078 DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
Henrik Boström8dfc90f2022-09-02 07:39:291079 kDirectionOutbound, attachment_id),
Harald Alvestrandc72af932018-01-11 16:18:191080 timestamp_us, RTCMediaStreamTrackKind::kVideo));
hbos9e302742017-01-20 10:47:101081 SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
1082 video_track, video_track_stats.get());
Henrik Boström646fda02019-05-22 13:49:421083 video_track_stats->media_source_id =
1084 RTCMediaSourceStatsIDFromKindAndAttachment(cricket::MEDIA_TYPE_VIDEO,
1085 attachment_id);
hbos9e302742017-01-20 10:47:101086 video_track_stats->remote_source = false;
1087 video_track_stats->detached = false;
Jonas Olssona4d87372019-07-05 17:08:331088 video_track_stats->frame_width =
1089 static_cast<uint32_t>(video_sender_info.send_frame_width);
1090 video_track_stats->frame_height =
1091 static_cast<uint32_t>(video_sender_info.send_frame_height);
hbosfefe0762017-01-20 14:14:251092 // TODO(hbos): Will reduce this by frames dropped due to congestion control
Harald Alvestrand89061872018-01-02 13:08:341093 // when available. https://crbug.com/659137
hbosfefe0762017-01-20 14:14:251094 video_track_stats->frames_sent = video_sender_info.frames_encoded;
Ilya Nikolaevskiy70473fc2018-02-28 15:35:031095 video_track_stats->huge_frames_sent = video_sender_info.huge_frames_sent;
hbos9e302742017-01-20 10:47:101096 return video_track_stats;
1097}
1098
Henrik Boström15166b22022-10-19 09:06:581099std::unique_ptr<DEPRECATED_RTCMediaStreamTrackStats>
hbos9e302742017-01-20 10:47:101100ProduceMediaStreamTrackStatsFromVideoReceiverInfo(
1101 int64_t timestamp_us,
1102 const VideoTrackInterface& video_track,
Harald Alvestrandc72af932018-01-11 16:18:191103 const cricket::VideoReceiverInfo& video_receiver_info,
1104 int attachment_id) {
Henrik Boström15166b22022-10-19 09:06:581105 std::unique_ptr<DEPRECATED_RTCMediaStreamTrackStats> video_track_stats(
1106 std::make_unique<DEPRECATED_RTCMediaStreamTrackStats>(
1107 DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
Henrik Boström8dfc90f2022-09-02 07:39:291108 kDirectionInbound, attachment_id),
Harald Alvestrandc72af932018-01-11 16:18:191109 timestamp_us, RTCMediaStreamTrackKind::kVideo));
hbos9e302742017-01-20 10:47:101110 SetMediaStreamTrackStatsFromMediaStreamTrackInterface(
1111 video_track, video_track_stats.get());
1112 video_track_stats->remote_source = true;
1113 video_track_stats->detached = false;
1114 if (video_receiver_info.frame_width > 0 &&
1115 video_receiver_info.frame_height > 0) {
Jonas Olssona4d87372019-07-05 17:08:331116 video_track_stats->frame_width =
1117 static_cast<uint32_t>(video_receiver_info.frame_width);
1118 video_track_stats->frame_height =
1119 static_cast<uint32_t>(video_receiver_info.frame_height);
hbos9e302742017-01-20 10:47:101120 }
Guido Urdaneta67378412019-05-28 15:38:081121 video_track_stats->jitter_buffer_delay =
1122 video_receiver_info.jitter_buffer_delay_seconds;
1123 video_track_stats->jitter_buffer_emitted_count =
1124 video_receiver_info.jitter_buffer_emitted_count;
hbos42f6d2f2017-01-20 11:56:501125 video_track_stats->frames_received = video_receiver_info.frames_received;
hbosf64941f2017-01-20 15:39:091126 // TODO(hbos): When we support receiving simulcast, this should be the total
1127 // number of frames correctly decoded, independent of which SSRC it was
1128 // received from. Since we don't support that, this is correct and is the same
Harald Alvestrand89061872018-01-02 13:08:341129 // value as "RTCInboundRTPStreamStats.framesDecoded". https://crbug.com/659137
hbosf64941f2017-01-20 15:39:091130 video_track_stats->frames_decoded = video_receiver_info.frames_decoded;
Johannes Kron0c141c52019-08-26 13:04:431131 video_track_stats->frames_dropped = video_receiver_info.frames_dropped;
Henrik Boströmc57a28c2022-10-06 09:59:051132
hbos9e302742017-01-20 10:47:101133 return video_track_stats;
1134}
1135
Harald Alvestrand89061872018-01-02 13:08:341136void ProduceSenderMediaTrackStats(
1137 int64_t timestamp_us,
1138 const TrackMediaInfoMap& track_media_info_map,
Steve Anton57858b32018-02-15 23:19:501139 std::vector<rtc::scoped_refptr<RtpSenderInternal>> senders,
Harald Alvestrand89061872018-01-02 13:08:341140 RTCStatsReport* report) {
1141 // This function iterates over the senders to generate outgoing track stats.
1142
Henrik Boströmfc67b452022-07-27 08:55:451143 // TODO(https://crbug.com/webrtc/14175): Stop collecting "track" stats,
1144 // they're deprecated.
Mirko Bonadei739baf02019-01-27 16:29:421145 for (const auto& sender : senders) {
Harald Alvestrand89061872018-01-02 13:08:341146 if (sender->media_type() == cricket::MEDIA_TYPE_AUDIO) {
1147 AudioTrackInterface* track =
1148 static_cast<AudioTrackInterface*>(sender->track().get());
1149 if (!track)
1150 continue;
Harald Alvestrandb8e12012018-01-23 14:28:161151 cricket::VoiceSenderInfo null_sender_info;
1152 const cricket::VoiceSenderInfo* voice_sender_info = &null_sender_info;
1153 // TODO(hta): Checking on ssrc is not proper. There should be a way
1154 // to see from a sender whether it's connected or not.
1155 // Related to https://crbug.com/8694 (using ssrc 0 to indicate "none")
Steve Anton57858b32018-02-15 23:19:501156 if (sender->ssrc() != 0) {
Harald Alvestrand76d29522018-01-30 13:43:291157 // When pc.close is called, sender info is discarded, so
1158 // we generate zeroes instead. Bug: It should be retained.
1159 // https://crbug.com/807174
Steve Anton57858b32018-02-15 23:19:501160 const cricket::VoiceSenderInfo* sender_info =
Harald Alvestrandb8e12012018-01-23 14:28:161161 track_media_info_map.GetVoiceSenderInfoBySsrc(sender->ssrc());
Harald Alvestrand76d29522018-01-30 13:43:291162 if (sender_info) {
1163 voice_sender_info = sender_info;
1164 } else {
Tommi19015512022-02-02 10:49:351165 RTC_DLOG(LS_INFO)
Harald Alvestrand76d29522018-01-30 13:43:291166 << "RTCStatsCollector: No voice sender info for sender with ssrc "
1167 << sender->ssrc();
1168 }
Harald Alvestrandb8e12012018-01-23 14:28:161169 }
Henrik Boström15166b22022-10-19 09:06:581170 std::unique_ptr<DEPRECATED_RTCMediaStreamTrackStats> audio_track_stats =
Harald Alvestrandc72af932018-01-11 16:18:191171 ProduceMediaStreamTrackStatsFromVoiceSenderInfo(
1172 timestamp_us, *track, *voice_sender_info, sender->AttachmentId());
Harald Alvestrand89061872018-01-02 13:08:341173 report->AddStats(std::move(audio_track_stats));
1174 } else if (sender->media_type() == cricket::MEDIA_TYPE_VIDEO) {
1175 VideoTrackInterface* track =
1176 static_cast<VideoTrackInterface*>(sender->track().get());
1177 if (!track)
1178 continue;
Harald Alvestrandb8e12012018-01-23 14:28:161179 cricket::VideoSenderInfo null_sender_info;
1180 const cricket::VideoSenderInfo* video_sender_info = &null_sender_info;
1181 // TODO(hta): Check on state not ssrc when state is available
Harald Alvestrand76d29522018-01-30 13:43:291182 // Related to https://bugs.webrtc.org/8694 (using ssrc 0 to indicate
1183 // "none")
Steve Anton57858b32018-02-15 23:19:501184 if (sender->ssrc() != 0) {
Harald Alvestrand76d29522018-01-30 13:43:291185 // When pc.close is called, sender info is discarded, so
1186 // we generate zeroes instead. Bug: It should be retained.
1187 // https://crbug.com/807174
Steve Anton57858b32018-02-15 23:19:501188 const cricket::VideoSenderInfo* sender_info =
Harald Alvestrandb8e12012018-01-23 14:28:161189 track_media_info_map.GetVideoSenderInfoBySsrc(sender->ssrc());
Harald Alvestrand76d29522018-01-30 13:43:291190 if (sender_info) {
1191 video_sender_info = sender_info;
1192 } else {
Tommi19015512022-02-02 10:49:351193 RTC_DLOG(LS_INFO)
1194 << "No video sender info for sender with ssrc " << sender->ssrc();
Harald Alvestrand76d29522018-01-30 13:43:291195 }
1196 }
Henrik Boström15166b22022-10-19 09:06:581197 std::unique_ptr<DEPRECATED_RTCMediaStreamTrackStats> video_track_stats =
Harald Alvestrandc72af932018-01-11 16:18:191198 ProduceMediaStreamTrackStatsFromVideoSenderInfo(
1199 timestamp_us, *track, *video_sender_info, sender->AttachmentId());
Harald Alvestrand89061872018-01-02 13:08:341200 report->AddStats(std::move(video_track_stats));
1201 } else {
Artem Titovd3251962021-11-15 15:57:071202 RTC_DCHECK_NOTREACHED();
Harald Alvestrand89061872018-01-02 13:08:341203 }
1204 }
1205}
1206
1207void ProduceReceiverMediaTrackStats(
1208 int64_t timestamp_us,
1209 const TrackMediaInfoMap& track_media_info_map,
Steve Anton57858b32018-02-15 23:19:501210 std::vector<rtc::scoped_refptr<RtpReceiverInternal>> receivers,
Harald Alvestrand89061872018-01-02 13:08:341211 RTCStatsReport* report) {
1212 // This function iterates over the receivers to find the remote tracks.
Mirko Bonadei739baf02019-01-27 16:29:421213 for (const auto& receiver : receivers) {
Harald Alvestrand89061872018-01-02 13:08:341214 if (receiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
1215 AudioTrackInterface* track =
1216 static_cast<AudioTrackInterface*>(receiver->track().get());
1217 const cricket::VoiceReceiverInfo* voice_receiver_info =
1218 track_media_info_map.GetVoiceReceiverInfo(*track);
1219 if (!voice_receiver_info) {
1220 continue;
1221 }
Henrik Boström15166b22022-10-19 09:06:581222 std::unique_ptr<DEPRECATED_RTCMediaStreamTrackStats> audio_track_stats =
Harald Alvestrand89061872018-01-02 13:08:341223 ProduceMediaStreamTrackStatsFromVoiceReceiverInfo(
Harald Alvestrandc72af932018-01-11 16:18:191224 timestamp_us, *track, *voice_receiver_info,
1225 receiver->AttachmentId());
Harald Alvestrand89061872018-01-02 13:08:341226 report->AddStats(std::move(audio_track_stats));
1227 } else if (receiver->media_type() == cricket::MEDIA_TYPE_VIDEO) {
1228 VideoTrackInterface* track =
1229 static_cast<VideoTrackInterface*>(receiver->track().get());
1230 const cricket::VideoReceiverInfo* video_receiver_info =
1231 track_media_info_map.GetVideoReceiverInfo(*track);
1232 if (!video_receiver_info) {
1233 continue;
1234 }
Henrik Boström15166b22022-10-19 09:06:581235 std::unique_ptr<DEPRECATED_RTCMediaStreamTrackStats> video_track_stats =
Harald Alvestrand89061872018-01-02 13:08:341236 ProduceMediaStreamTrackStatsFromVideoReceiverInfo(
Harald Alvestrandc72af932018-01-11 16:18:191237 timestamp_us, *track, *video_receiver_info,
1238 receiver->AttachmentId());
Harald Alvestrand89061872018-01-02 13:08:341239 report->AddStats(std::move(video_track_stats));
1240 } else {
Artem Titovd3251962021-11-15 15:57:071241 RTC_DCHECK_NOTREACHED();
Harald Alvestrand89061872018-01-02 13:08:341242 }
1243 }
1244}
1245
Henrik Boström5b3541f2018-03-19 12:52:561246rtc::scoped_refptr<RTCStatsReport> CreateReportFilteredBySelector(
1247 bool filter_by_sender_selector,
1248 rtc::scoped_refptr<const RTCStatsReport> report,
1249 rtc::scoped_refptr<RtpSenderInternal> sender_selector,
1250 rtc::scoped_refptr<RtpReceiverInternal> receiver_selector) {
1251 std::vector<std::string> rtpstream_ids;
1252 if (filter_by_sender_selector) {
1253 // Filter mode: RTCStatsCollector::RequestInfo::kSenderSelector
1254 if (sender_selector) {
1255 // Find outbound-rtp(s) of the sender, i.e. the outbound-rtp(s) that
1256 // reference the sender stats.
1257 // Because we do not implement sender stats, we look at outbound-rtp(s)
1258 // that reference the track attachment stats for the sender instead.
1259 std::string track_id =
Henrik Boström15166b22022-10-19 09:06:581260 DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
Henrik Boström8dfc90f2022-09-02 07:39:291261 kDirectionOutbound, sender_selector->AttachmentId());
Henrik Boström5b3541f2018-03-19 12:52:561262 for (const auto& stats : *report) {
1263 if (stats.type() != RTCOutboundRTPStreamStats::kType)
1264 continue;
1265 const auto& outbound_rtp = stats.cast_to<RTCOutboundRTPStreamStats>();
1266 if (outbound_rtp.track_id.is_defined() &&
1267 *outbound_rtp.track_id == track_id) {
1268 rtpstream_ids.push_back(outbound_rtp.id());
1269 }
1270 }
1271 }
1272 } else {
1273 // Filter mode: RTCStatsCollector::RequestInfo::kReceiverSelector
1274 if (receiver_selector) {
1275 // Find inbound-rtp(s) of the receiver, i.e. the inbound-rtp(s) that
1276 // reference the receiver stats.
1277 // Because we do not implement receiver stats, we look at inbound-rtp(s)
1278 // that reference the track attachment stats for the receiver instead.
1279 std::string track_id =
Henrik Boström15166b22022-10-19 09:06:581280 DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
Henrik Boström8dfc90f2022-09-02 07:39:291281 kDirectionInbound, receiver_selector->AttachmentId());
Henrik Boström5b3541f2018-03-19 12:52:561282 for (const auto& stats : *report) {
1283 if (stats.type() != RTCInboundRTPStreamStats::kType)
1284 continue;
1285 const auto& inbound_rtp = stats.cast_to<RTCInboundRTPStreamStats>();
1286 if (inbound_rtp.track_id.is_defined() &&
1287 *inbound_rtp.track_id == track_id) {
1288 rtpstream_ids.push_back(inbound_rtp.id());
1289 }
1290 }
1291 }
1292 }
1293 if (rtpstream_ids.empty())
Philipp Hancke036b3fd2022-10-12 17:12:231294 return RTCStatsReport::Create(report->timestamp());
Henrik Boström5b3541f2018-03-19 12:52:561295 return TakeReferencedStats(report->Copy(), rtpstream_ids);
1296}
1297
hboscc555c52016-10-18 19:48:311298} // namespace
1299
Henrik Boström69d23c92022-09-26 12:13:171300RTCStatsCollector::CertificateStatsPair
1301RTCStatsCollector::CertificateStatsPair::Copy() const {
1302 CertificateStatsPair copy;
1303 copy.local = local ? local->Copy() : nullptr;
1304 copy.remote = remote ? remote->Copy() : nullptr;
1305 return copy;
1306}
1307
Henrik Boström5b3541f2018-03-19 12:52:561308RTCStatsCollector::RequestInfo::RequestInfo(
1309 rtc::scoped_refptr<RTCStatsCollectorCallback> callback)
1310 : RequestInfo(FilterMode::kAll, std::move(callback), nullptr, nullptr) {}
1311
1312RTCStatsCollector::RequestInfo::RequestInfo(
1313 rtc::scoped_refptr<RtpSenderInternal> selector,
1314 rtc::scoped_refptr<RTCStatsCollectorCallback> callback)
1315 : RequestInfo(FilterMode::kSenderSelector,
1316 std::move(callback),
1317 std::move(selector),
1318 nullptr) {}
1319
1320RTCStatsCollector::RequestInfo::RequestInfo(
1321 rtc::scoped_refptr<RtpReceiverInternal> selector,
1322 rtc::scoped_refptr<RTCStatsCollectorCallback> callback)
1323 : RequestInfo(FilterMode::kReceiverSelector,
1324 std::move(callback),
1325 nullptr,
1326 std::move(selector)) {}
1327
1328RTCStatsCollector::RequestInfo::RequestInfo(
1329 RTCStatsCollector::RequestInfo::FilterMode filter_mode,
1330 rtc::scoped_refptr<RTCStatsCollectorCallback> callback,
1331 rtc::scoped_refptr<RtpSenderInternal> sender_selector,
1332 rtc::scoped_refptr<RtpReceiverInternal> receiver_selector)
1333 : filter_mode_(filter_mode),
1334 callback_(std::move(callback)),
1335 sender_selector_(std::move(sender_selector)),
1336 receiver_selector_(std::move(receiver_selector)) {
1337 RTC_DCHECK(callback_);
1338 RTC_DCHECK(!sender_selector_ || !receiver_selector_);
1339}
1340
hbosc82f2e12016-09-05 08:36:501341rtc::scoped_refptr<RTCStatsCollector> RTCStatsCollector::Create(
Steve Anton2d8609c2018-01-24 00:38:461342 PeerConnectionInternal* pc,
1343 int64_t cache_lifetime_us) {
Tommi87f70902021-04-27 12:43:081344 return rtc::make_ref_counted<RTCStatsCollector>(pc, cache_lifetime_us);
hbosc82f2e12016-09-05 08:36:501345}
1346
Steve Anton2d8609c2018-01-24 00:38:461347RTCStatsCollector::RTCStatsCollector(PeerConnectionInternal* pc,
hbosc82f2e12016-09-05 08:36:501348 int64_t cache_lifetime_us)
hbosd565b732016-08-30 21:04:351349 : pc_(pc),
Steve Anton978b8762017-09-29 19:15:021350 signaling_thread_(pc->signaling_thread()),
1351 worker_thread_(pc->worker_thread()),
1352 network_thread_(pc->network_thread()),
hbosc82f2e12016-09-05 08:36:501353 num_pending_partial_reports_(0),
1354 partial_report_timestamp_us_(0),
Henrik Boström40b030e2019-02-28 08:49:311355 network_report_event_(true /* manual_reset */,
1356 true /* initially_signaled */),
hbos0e6758d2016-08-31 14:57:361357 cache_timestamp_us_(0),
1358 cache_lifetime_us_(cache_lifetime_us) {
hbosd565b732016-08-30 21:04:351359 RTC_DCHECK(pc_);
hbosc82f2e12016-09-05 08:36:501360 RTC_DCHECK(signaling_thread_);
1361 RTC_DCHECK(worker_thread_);
1362 RTC_DCHECK(network_thread_);
hbos0e6758d2016-08-31 14:57:361363 RTC_DCHECK_GE(cache_lifetime_us_, 0);
Mirko Bonadeie0bc8d22022-02-08 07:41:251364 pc_->SignalSctpDataChannelCreated().connect(
1365 this, &RTCStatsCollector::OnSctpDataChannelCreated);
hbosd565b732016-08-30 21:04:351366}
1367
hbosb78306a2016-12-19 13:06:571368RTCStatsCollector::~RTCStatsCollector() {
1369 RTC_DCHECK_EQ(num_pending_partial_reports_, 0);
1370}
1371
hbosc82f2e12016-09-05 08:36:501372void RTCStatsCollector::GetStatsReport(
1373 rtc::scoped_refptr<RTCStatsCollectorCallback> callback) {
Henrik Boström5b3541f2018-03-19 12:52:561374 GetStatsReportInternal(RequestInfo(std::move(callback)));
1375}
1376
1377void RTCStatsCollector::GetStatsReport(
1378 rtc::scoped_refptr<RtpSenderInternal> selector,
1379 rtc::scoped_refptr<RTCStatsCollectorCallback> callback) {
1380 GetStatsReportInternal(RequestInfo(std::move(selector), std::move(callback)));
1381}
1382
1383void RTCStatsCollector::GetStatsReport(
1384 rtc::scoped_refptr<RtpReceiverInternal> selector,
1385 rtc::scoped_refptr<RTCStatsCollectorCallback> callback) {
1386 GetStatsReportInternal(RequestInfo(std::move(selector), std::move(callback)));
1387}
1388
1389void RTCStatsCollector::GetStatsReportInternal(
1390 RTCStatsCollector::RequestInfo request) {
Tomas Gunnarsson67b1fa22021-04-08 13:18:051391 RTC_DCHECK_RUN_ON(signaling_thread_);
Henrik Boström5b3541f2018-03-19 12:52:561392 requests_.push_back(std::move(request));
hbosc82f2e12016-09-05 08:36:501393
hbos0e6758d2016-08-31 14:57:361394 // "Now" using a monotonically increasing timer.
1395 int64_t cache_now_us = rtc::TimeMicros();
1396 if (cached_report_ &&
1397 cache_now_us - cache_timestamp_us_ <= cache_lifetime_us_) {
Taylor Brandstetter25e022f2018-03-08 17:53:471398 // We have a fresh cached report to deliver. Deliver asynchronously, since
1399 // the caller may not be expecting a synchronous callback, and it avoids
1400 // reentrancy problems.
Danil Chapovalova30439b2022-07-07 08:08:491401 signaling_thread_->PostTask(
1402 absl::bind_front(&RTCStatsCollector::DeliverCachedReport,
1403 rtc::scoped_refptr<RTCStatsCollector>(this),
1404 cached_report_, std::move(requests_)));
hbosc82f2e12016-09-05 08:36:501405 } else if (!num_pending_partial_reports_) {
1406 // Only start gathering stats if we're not already gathering stats. In the
Artem Titov880fa812021-07-30 20:30:231407 // case of already gathering stats, `callback_` will be invoked when there
hbosc82f2e12016-09-05 08:36:501408 // are no more pending partial reports.
1409
1410 // "Now" using a system clock, relative to the UNIX epoch (Jan 1, 1970,
1411 // UTC), in microseconds. The system clock could be modified and is not
1412 // necessarily monotonically increasing.
nissecdf37a92016-09-14 06:41:471413 int64_t timestamp_us = rtc::TimeUTCMicros();
hbosc82f2e12016-09-05 08:36:501414
hbosf415f8a2017-01-02 12:28:511415 num_pending_partial_reports_ = 2;
hbosc82f2e12016-09-05 08:36:501416 partial_report_timestamp_us_ = cache_now_us;
hbosdf6075a2016-12-19 12:58:021417
Artem Titov880fa812021-07-30 20:30:231418 // Prepare `transceiver_stats_infos_` and `call_stats_` for use in
1419 // `ProducePartialResultsOnNetworkThread` and
1420 // `ProducePartialResultsOnSignalingThread`.
Tomas Gunnarssonbfd9ba82021-04-18 09:55:571421 PrepareTransceiverStatsInfosAndCallStats_s_w_n();
Artem Titov880fa812021-07-30 20:30:231422 // Don't touch `network_report_` on the signaling thread until
Henrik Boström40b030e2019-02-28 08:49:311423 // ProducePartialResultsOnNetworkThread() has signaled the
Artem Titov880fa812021-07-30 20:30:231424 // `network_report_event_`.
Henrik Boström40b030e2019-02-28 08:49:311425 network_report_event_.Reset();
Niels Möller4bab23f2021-01-18 08:24:331426 rtc::scoped_refptr<RTCStatsCollector> collector(this);
Tomas Gunnarssonbfd9ba82021-04-18 09:55:571427 network_thread_->PostTask(
Tomas Gunnarssonbfd9ba82021-04-18 09:55:571428 [collector, sctp_transport_name = pc_->sctp_transport_name(),
1429 timestamp_us]() mutable {
1430 collector->ProducePartialResultsOnNetworkThread(
1431 timestamp_us, std::move(sctp_transport_name));
1432 });
hbosf415f8a2017-01-02 12:28:511433 ProducePartialResultsOnSignalingThread(timestamp_us);
hbos0e6758d2016-08-31 14:57:361434 }
hbosd565b732016-08-30 21:04:351435}
1436
1437void RTCStatsCollector::ClearCachedStatsReport() {
Tomas Gunnarsson67b1fa22021-04-08 13:18:051438 RTC_DCHECK_RUN_ON(signaling_thread_);
hbosd565b732016-08-30 21:04:351439 cached_report_ = nullptr;
Henrik Boströmb3dd1732022-09-30 15:22:441440 MutexLock lock(&cached_certificates_mutex_);
Henrik Boström69d23c92022-09-26 12:13:171441 cached_certificates_by_transport_.clear();
hbosd565b732016-08-30 21:04:351442}
1443
hbosb78306a2016-12-19 13:06:571444void RTCStatsCollector::WaitForPendingRequest() {
Tomas Gunnarsson67b1fa22021-04-08 13:18:051445 RTC_DCHECK_RUN_ON(signaling_thread_);
Artem Titov880fa812021-07-30 20:30:231446 // If a request is pending, blocks until the `network_report_event_` is
Henrik Boström40b030e2019-02-28 08:49:311447 // signaled and then delivers the result. Otherwise this is a NO-OP.
1448 MergeNetworkReport_s();
hbosb78306a2016-12-19 13:06:571449}
1450
hbosc82f2e12016-09-05 08:36:501451void RTCStatsCollector::ProducePartialResultsOnSignalingThread(
1452 int64_t timestamp_us) {
Tomas Gunnarsson67b1fa22021-04-08 13:18:051453 RTC_DCHECK_RUN_ON(signaling_thread_);
Henrik Boströme88c95e2020-07-08 09:18:501454 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1455
Philipp Hancke036b3fd2022-10-12 17:12:231456 partial_report_ = RTCStatsReport::Create(Timestamp::Micros(timestamp_us));
hbosc82f2e12016-09-05 08:36:501457
Henrik Boström40b030e2019-02-28 08:49:311458 ProducePartialResultsOnSignalingThreadImpl(timestamp_us,
1459 partial_report_.get());
hbosc82f2e12016-09-05 08:36:501460
Henrik Boström40b030e2019-02-28 08:49:311461 // ProducePartialResultsOnSignalingThread() is running synchronously on the
1462 // signaling thread, so it is always the first partial result delivered on the
1463 // signaling thread. The request is not complete until MergeNetworkReport_s()
1464 // happens; we don't have to do anything here.
1465 RTC_DCHECK_GT(num_pending_partial_reports_, 1);
1466 --num_pending_partial_reports_;
1467}
1468
1469void RTCStatsCollector::ProducePartialResultsOnSignalingThreadImpl(
1470 int64_t timestamp_us,
1471 RTCStatsReport* partial_report) {
Tomas Gunnarsson67b1fa22021-04-08 13:18:051472 RTC_DCHECK_RUN_ON(signaling_thread_);
Henrik Boströme88c95e2020-07-08 09:18:501473 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1474
Henrik Boström40b030e2019-02-28 08:49:311475 ProduceDataChannelStats_s(timestamp_us, partial_report);
1476 ProduceMediaStreamStats_s(timestamp_us, partial_report);
1477 ProduceMediaStreamTrackStats_s(timestamp_us, partial_report);
Henrik Boström646fda02019-05-22 13:49:421478 ProduceMediaSourceStats_s(timestamp_us, partial_report);
Henrik Boström40b030e2019-02-28 08:49:311479 ProducePeerConnectionStats_s(timestamp_us, partial_report);
hbosc82f2e12016-09-05 08:36:501480}
1481
hbosc82f2e12016-09-05 08:36:501482void RTCStatsCollector::ProducePartialResultsOnNetworkThread(
Tomas Gunnarssonbfd9ba82021-04-18 09:55:571483 int64_t timestamp_us,
1484 absl::optional<std::string> sctp_transport_name) {
Markus Handell518669d2021-06-07 11:30:461485 TRACE_EVENT0("webrtc",
1486 "RTCStatsCollector::ProducePartialResultsOnNetworkThread");
Tomas Gunnarsson67b1fa22021-04-08 13:18:051487 RTC_DCHECK_RUN_ON(network_thread_);
Henrik Boströme88c95e2020-07-08 09:18:501488 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1489
Artem Titov880fa812021-07-30 20:30:231490 // Touching `network_report_` on this thread is safe by this method because
1491 // `network_report_event_` is reset before this method is invoked.
Philipp Hancke036b3fd2022-10-12 17:12:231492 network_report_ = RTCStatsReport::Create(Timestamp::Micros(timestamp_us));
hbosc82f2e12016-09-05 08:36:501493
Tomas Gunnarssonbfd9ba82021-04-18 09:55:571494 std::set<std::string> transport_names;
1495 if (sctp_transport_name) {
1496 transport_names.emplace(std::move(*sctp_transport_name));
1497 }
1498
1499 for (const auto& info : transceiver_stats_infos_) {
1500 if (info.transport_name)
1501 transport_names.insert(*info.transport_name);
1502 }
1503
Steve Anton5dfde182018-02-06 18:34:401504 std::map<std::string, cricket::TransportStats> transport_stats_by_name =
Tomas Gunnarssonbfd9ba82021-04-18 09:55:571505 pc_->GetTransportStatsByNames(transport_names);
Steve Anton5dfde182018-02-06 18:34:401506 std::map<std::string, CertificateStatsPair> transport_cert_stats =
1507 PrepareTransportCertificateStats_n(transport_stats_by_name);
1508
Henrik Boström40b030e2019-02-28 08:49:311509 ProducePartialResultsOnNetworkThreadImpl(
1510 timestamp_us, transport_stats_by_name, transport_cert_stats,
1511 network_report_.get());
Mirko Bonadeica890ee2019-02-15 21:10:401512
Artem Titov880fa812021-07-30 20:30:231513 // Signal that it is now safe to touch `network_report_` on the signaling
Henrik Boström40b030e2019-02-28 08:49:311514 // thread, and post a task to merge it into the final results.
1515 network_report_event_.Set();
Niels Möller4bab23f2021-01-18 08:24:331516 rtc::scoped_refptr<RTCStatsCollector> collector(this);
Henrik Boström40b030e2019-02-28 08:49:311517 signaling_thread_->PostTask(
Henrik Boström2deee4b2022-01-20 10:58:051518 [collector] { collector->MergeNetworkReport_s(); });
Henrik Boström05d43c62019-02-15 09:23:081519}
1520
Henrik Boström40b030e2019-02-28 08:49:311521void RTCStatsCollector::ProducePartialResultsOnNetworkThreadImpl(
1522 int64_t timestamp_us,
1523 const std::map<std::string, cricket::TransportStats>&
1524 transport_stats_by_name,
1525 const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
1526 RTCStatsReport* partial_report) {
Tomas Gunnarsson67b1fa22021-04-08 13:18:051527 RTC_DCHECK_RUN_ON(network_thread_);
Henrik Boströme88c95e2020-07-08 09:18:501528 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1529
Henrik Boström40b030e2019-02-28 08:49:311530 ProduceCertificateStats_n(timestamp_us, transport_cert_stats, partial_report);
Henrik Boström40b030e2019-02-28 08:49:311531 ProduceIceCandidateAndPairStats_n(timestamp_us, transport_stats_by_name,
1532 call_stats_, partial_report);
Henrik Boström40b030e2019-02-28 08:49:311533 ProduceTransportStats_n(timestamp_us, transport_stats_by_name,
1534 transport_cert_stats, partial_report);
Henrik Boström883eefc2019-05-27 11:40:251535 ProduceRTPStreamStats_n(timestamp_us, transceiver_stats_infos_,
1536 partial_report);
Henrik Boström40b030e2019-02-28 08:49:311537}
1538
1539void RTCStatsCollector::MergeNetworkReport_s() {
Tomas Gunnarsson67b1fa22021-04-08 13:18:051540 RTC_DCHECK_RUN_ON(signaling_thread_);
Artem Titov880fa812021-07-30 20:30:231541 // The `network_report_event_` must be signaled for it to be safe to touch
1542 // `network_report_`. This is normally not blocking, but if
Henrik Boström40b030e2019-02-28 08:49:311543 // WaitForPendingRequest() is called while a request is pending, we might have
Artem Titov880fa812021-07-30 20:30:231544 // to wait until the network thread is done touching `network_report_`.
Henrik Boström40b030e2019-02-28 08:49:311545 network_report_event_.Wait(rtc::Event::kForever);
1546 if (!network_report_) {
1547 // Normally, MergeNetworkReport_s() is executed because it is posted from
1548 // the network thread. But if WaitForPendingRequest() is called while a
1549 // request is pending, an early call to MergeNetworkReport_s() is made,
Artem Titov880fa812021-07-30 20:30:231550 // merging the report and setting `network_report_` to null. If so, when the
Henrik Boström40b030e2019-02-28 08:49:311551 // previously posted MergeNetworkReport_s() is later executed, the report is
1552 // already null and nothing needs to be done here.
hbosc82f2e12016-09-05 08:36:501553 return;
1554 }
Mirko Bonadeica890ee2019-02-15 21:10:401555 RTC_DCHECK_GT(num_pending_partial_reports_, 0);
Henrik Boström40b030e2019-02-28 08:49:311556 RTC_DCHECK(partial_report_);
1557 partial_report_->TakeMembersFrom(network_report_);
1558 network_report_ = nullptr;
Mirko Bonadeica890ee2019-02-15 21:10:401559 --num_pending_partial_reports_;
Artem Titov880fa812021-07-30 20:30:231560 // `network_report_` is currently the only partial report collected
1561 // asynchronously, so `num_pending_partial_reports_` must now be 0 and we are
Henrik Boström40b030e2019-02-28 08:49:311562 // ready to deliver the result.
1563 RTC_DCHECK_EQ(num_pending_partial_reports_, 0);
1564 cache_timestamp_us_ = partial_report_timestamp_us_;
1565 cached_report_ = partial_report_;
1566 partial_report_ = nullptr;
1567 transceiver_stats_infos_.clear();
1568 // Trace WebRTC Stats when getStats is called on Javascript.
1569 // This allows access to WebRTC stats from trace logs. To enable them,
1570 // select the "webrtc_stats" category when recording traces.
1571 TRACE_EVENT_INSTANT1("webrtc_stats", "webrtc_stats", "report",
1572 cached_report_->ToJson());
Mirko Bonadeica890ee2019-02-15 21:10:401573
Artem Titov880fa812021-07-30 20:30:231574 // Deliver report and clear `requests_`.
Henrik Boström40b030e2019-02-28 08:49:311575 std::vector<RequestInfo> requests;
1576 requests.swap(requests_);
1577 DeliverCachedReport(cached_report_, std::move(requests));
hbosc82f2e12016-09-05 08:36:501578}
1579
Taylor Brandstetter25e022f2018-03-08 17:53:471580void RTCStatsCollector::DeliverCachedReport(
1581 rtc::scoped_refptr<const RTCStatsReport> cached_report,
Henrik Boström5b3541f2018-03-19 12:52:561582 std::vector<RTCStatsCollector::RequestInfo> requests) {
Tomas Gunnarsson67b1fa22021-04-08 13:18:051583 RTC_DCHECK_RUN_ON(signaling_thread_);
Henrik Boström5b3541f2018-03-19 12:52:561584 RTC_DCHECK(!requests.empty());
Taylor Brandstetter25e022f2018-03-08 17:53:471585 RTC_DCHECK(cached_report);
Taylor Brandstetter87d5a742018-03-06 17:42:251586
Henrik Boström5b3541f2018-03-19 12:52:561587 for (const RequestInfo& request : requests) {
1588 if (request.filter_mode() == RequestInfo::FilterMode::kAll) {
1589 request.callback()->OnStatsDelivered(cached_report);
1590 } else {
1591 bool filter_by_sender_selector;
1592 rtc::scoped_refptr<RtpSenderInternal> sender_selector;
1593 rtc::scoped_refptr<RtpReceiverInternal> receiver_selector;
1594 if (request.filter_mode() == RequestInfo::FilterMode::kSenderSelector) {
1595 filter_by_sender_selector = true;
1596 sender_selector = request.sender_selector();
1597 } else {
1598 RTC_DCHECK(request.filter_mode() ==
1599 RequestInfo::FilterMode::kReceiverSelector);
1600 filter_by_sender_selector = false;
1601 receiver_selector = request.receiver_selector();
1602 }
1603 request.callback()->OnStatsDelivered(CreateReportFilteredBySelector(
1604 filter_by_sender_selector, cached_report, sender_selector,
1605 receiver_selector));
1606 }
hbosc82f2e12016-09-05 08:36:501607 }
hbosd565b732016-08-30 21:04:351608}
1609
hbosdf6075a2016-12-19 12:58:021610void RTCStatsCollector::ProduceCertificateStats_n(
hbos2fa7c672016-10-24 11:00:051611 int64_t timestamp_us,
1612 const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
hbos6ab97ce02016-10-03 21:16:561613 RTCStatsReport* report) const {
Tomas Gunnarsson67b1fa22021-04-08 13:18:051614 RTC_DCHECK_RUN_ON(network_thread_);
Henrik Boströme88c95e2020-07-08 09:18:501615 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1616
hbos02ba2112016-10-28 12:14:531617 for (const auto& transport_cert_stats_pair : transport_cert_stats) {
1618 if (transport_cert_stats_pair.second.local) {
1619 ProduceCertificateStatsFromSSLCertificateStats(
1620 timestamp_us, *transport_cert_stats_pair.second.local.get(), report);
hbos6ab97ce02016-10-03 21:16:561621 }
hbos02ba2112016-10-28 12:14:531622 if (transport_cert_stats_pair.second.remote) {
1623 ProduceCertificateStatsFromSSLCertificateStats(
1624 timestamp_us, *transport_cert_stats_pair.second.remote.get(), report);
hbos6ab97ce02016-10-03 21:16:561625 }
1626 }
1627}
1628
hboscc555c52016-10-18 19:48:311629void RTCStatsCollector::ProduceDataChannelStats_s(
Jonas Olssona4d87372019-07-05 17:08:331630 int64_t timestamp_us,
1631 RTCStatsReport* report) const {
Tomas Gunnarsson2e94de52020-06-16 14:54:101632 RTC_DCHECK_RUN_ON(signaling_thread_);
Henrik Boströme88c95e2020-07-08 09:18:501633 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
Taylor Brandstetter3a034e12020-07-09 22:32:341634 std::vector<DataChannelStats> data_stats = pc_->GetDataChannelStats();
Tomas Gunnarsson2e94de52020-06-16 14:54:101635 for (const auto& stats : data_stats) {
hboscc555c52016-10-18 19:48:311636 std::unique_ptr<RTCDataChannelStats> data_channel_stats(
Philipp Hanckeb5cf12d2022-09-06 09:55:311637 std::make_unique<RTCDataChannelStats>(
1638 "D" + rtc::ToString(stats.internal_id), timestamp_us));
Tomas Gunnarsson2e94de52020-06-16 14:54:101639 data_channel_stats->label = std::move(stats.label);
1640 data_channel_stats->protocol = std::move(stats.protocol);
1641 data_channel_stats->data_channel_identifier = stats.id;
1642 data_channel_stats->state = DataStateToRTCDataChannelState(stats.state);
1643 data_channel_stats->messages_sent = stats.messages_sent;
1644 data_channel_stats->bytes_sent = stats.bytes_sent;
1645 data_channel_stats->messages_received = stats.messages_received;
1646 data_channel_stats->bytes_received = stats.bytes_received;
hboscc555c52016-10-18 19:48:311647 report->AddStats(std::move(data_channel_stats));
1648 }
1649}
1650
hbosdf6075a2016-12-19 12:58:021651void RTCStatsCollector::ProduceIceCandidateAndPairStats_n(
stefanf79ade12017-06-02 13:44:031652 int64_t timestamp_us,
Steve Anton5dfde182018-02-06 18:34:401653 const std::map<std::string, cricket::TransportStats>&
1654 transport_stats_by_name,
stefanf79ade12017-06-02 13:44:031655 const Call::Stats& call_stats,
1656 RTCStatsReport* report) const {
Tomas Gunnarsson67b1fa22021-04-08 13:18:051657 RTC_DCHECK_RUN_ON(network_thread_);
Henrik Boströme88c95e2020-07-08 09:18:501658 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1659
Steve Anton5dfde182018-02-06 18:34:401660 for (const auto& entry : transport_stats_by_name) {
1661 const std::string& transport_name = entry.first;
1662 const cricket::TransportStats& transport_stats = entry.second;
1663 for (const auto& channel_stats : transport_stats.channel_stats) {
hbos0583b282016-11-30 09:50:141664 std::string transport_id = RTCTransportStatsIDFromTransportChannel(
Steve Anton5dfde182018-02-06 18:34:401665 transport_name, channel_stats.component);
Philipp Hancke6e57ca22022-06-09 13:58:181666 for (const auto& info :
Jonas Oreland149dc722019-08-28 06:10:271667 channel_stats.ice_transport_stats.connection_infos) {
hbosc47a0c32016-10-11 21:54:491668 std::unique_ptr<RTCIceCandidatePairStats> candidate_pair_stats(
Philipp Hanckeb5cf12d2022-09-06 09:55:311669 std::make_unique<RTCIceCandidatePairStats>(
hbos2fa7c672016-10-24 11:00:051670 RTCIceCandidatePairStatsIDFromConnectionInfo(info),
1671 timestamp_us));
hbosc47a0c32016-10-11 21:54:491672
hbos0583b282016-11-30 09:50:141673 candidate_pair_stats->transport_id = transport_id;
hbosab9f6e42016-10-07 09:18:471674 // TODO(hbos): There could be other candidates that are not paired with
1675 // anything. We don't have a complete list. Local candidates come from
1676 // Port objects, and prflx candidates (both local and remote) are only
Harald Alvestrand89061872018-01-02 13:08:341677 // stored in candidate pairs. https://crbug.com/632723
hbos02ba2112016-10-28 12:14:531678 candidate_pair_stats->local_candidate_id = ProduceIceCandidateStats(
hbosb4e426e2017-01-02 17:59:311679 timestamp_us, info.local_candidate, true, transport_id, report);
hbos02ba2112016-10-28 12:14:531680 candidate_pair_stats->remote_candidate_id = ProduceIceCandidateStats(
hbosb4e426e2017-01-02 17:59:311681 timestamp_us, info.remote_candidate, false, transport_id, report);
hbos06495bc2017-01-02 16:08:181682 candidate_pair_stats->state =
1683 IceCandidatePairStateToRTCStatsIceCandidatePairState(info.state);
1684 candidate_pair_stats->priority = info.priority;
hbos92eaec62017-02-27 09:38:081685 candidate_pair_stats->nominated = info.nominated;
hbosc47a0c32016-10-11 21:54:491686 // TODO(hbos): This writable is different than the spec. It goes to
1687 // false after a certain amount of time without a response passes.
Harald Alvestrand89061872018-01-02 13:08:341688 // https://crbug.com/633550
hbosc47a0c32016-10-11 21:54:491689 candidate_pair_stats->writable = info.writable;
Taylor Brandstetter79326ea2021-09-28 22:09:531690 // Note that sent_total_packets includes discarded packets but
1691 // sent_total_bytes does not.
1692 candidate_pair_stats->packets_sent = static_cast<uint64_t>(
1693 info.sent_total_packets - info.sent_discarded_packets);
1694 candidate_pair_stats->packets_discarded_on_send =
1695 static_cast<uint64_t>(info.sent_discarded_packets);
1696 candidate_pair_stats->packets_received =
1697 static_cast<uint64_t>(info.packets_received);
hbosc47a0c32016-10-11 21:54:491698 candidate_pair_stats->bytes_sent =
1699 static_cast<uint64_t>(info.sent_total_bytes);
Taylor Brandstetter79326ea2021-09-28 22:09:531700 candidate_pair_stats->bytes_discarded_on_send =
1701 static_cast<uint64_t>(info.sent_discarded_bytes);
hbosc47a0c32016-10-11 21:54:491702 candidate_pair_stats->bytes_received =
1703 static_cast<uint64_t>(info.recv_total_bytes);
hbosbf8d3e52017-02-28 14:34:471704 candidate_pair_stats->total_round_trip_time =
1705 static_cast<double>(info.total_round_trip_time_ms) /
1706 rtc::kNumMillisecsPerSec;
Philipp Hancke42e5ed32022-11-02 15:08:161707 if (info.current_round_trip_time_ms.has_value()) {
hbosbf8d3e52017-02-28 14:34:471708 candidate_pair_stats->current_round_trip_time =
1709 static_cast<double>(*info.current_round_trip_time_ms) /
1710 rtc::kNumMillisecsPerSec;
1711 }
stefanf79ade12017-06-02 13:44:031712 if (info.best_connection) {
hbos338f78a2017-02-07 14:41:211713 // The bandwidth estimations we have are for the selected candidate
1714 // pair ("info.best_connection").
stefanf79ade12017-06-02 13:44:031715 RTC_DCHECK_GE(call_stats.send_bandwidth_bps, 0);
1716 RTC_DCHECK_GE(call_stats.recv_bandwidth_bps, 0);
1717 if (call_stats.send_bandwidth_bps > 0) {
hbos338f78a2017-02-07 14:41:211718 candidate_pair_stats->available_outgoing_bitrate =
stefanf79ade12017-06-02 13:44:031719 static_cast<double>(call_stats.send_bandwidth_bps);
hbos338f78a2017-02-07 14:41:211720 }
stefanf79ade12017-06-02 13:44:031721 if (call_stats.recv_bandwidth_bps > 0) {
hbos338f78a2017-02-07 14:41:211722 candidate_pair_stats->available_incoming_bitrate =
stefanf79ade12017-06-02 13:44:031723 static_cast<double>(call_stats.recv_bandwidth_bps);
hbos338f78a2017-02-07 14:41:211724 }
1725 }
hbosd82f5122016-12-09 12:12:391726 candidate_pair_stats->requests_received =
1727 static_cast<uint64_t>(info.recv_ping_requests);
Henrik Boström839439a2022-09-06 09:16:361728 candidate_pair_stats->requests_sent =
1729 static_cast<uint64_t>(info.sent_ping_requests_total);
hbosc47a0c32016-10-11 21:54:491730 candidate_pair_stats->responses_received =
1731 static_cast<uint64_t>(info.recv_ping_responses);
1732 candidate_pair_stats->responses_sent =
1733 static_cast<uint64_t>(info.sent_ping_responses);
hbose448dd52016-12-12 09:22:531734 RTC_DCHECK_GE(info.sent_ping_requests_total,
1735 info.sent_ping_requests_before_first_response);
1736 candidate_pair_stats->consent_requests_sent = static_cast<uint64_t>(
1737 info.sent_ping_requests_total -
1738 info.sent_ping_requests_before_first_response);
hbosc47a0c32016-10-11 21:54:491739
Philipp Hancke42e5ed32022-11-02 15:08:161740 if (info.last_data_received.has_value()) {
Philipp Hancke0487c572022-11-01 16:03:011741 candidate_pair_stats->last_packet_received_timestamp =
1742 static_cast<double>(info.last_data_received->ms());
1743 }
1744 if (info.last_data_sent) {
1745 candidate_pair_stats->last_packet_sent_timestamp =
1746 static_cast<double>(info.last_data_sent->ms());
1747 }
1748
hbosc47a0c32016-10-11 21:54:491749 report->AddStats(std::move(candidate_pair_stats));
hbosab9f6e42016-10-07 09:18:471750 }
Philipp Hancke6e57ca22022-06-09 13:58:181751
1752 // Produce local candidate stats. If a transport exists these will already
1753 // have been produced.
1754 for (const auto& candidate_stats :
1755 channel_stats.ice_transport_stats.candidate_stats_list) {
1756 const auto& candidate = candidate_stats.candidate();
1757 ProduceIceCandidateStats(timestamp_us, candidate, true, transport_id,
1758 report);
1759 }
hbosab9f6e42016-10-07 09:18:471760 }
1761 }
1762}
1763
Steve Anton57858b32018-02-15 23:19:501764void RTCStatsCollector::ProduceMediaStreamStats_s(
1765 int64_t timestamp_us,
1766 RTCStatsReport* report) const {
Tomas Gunnarsson67b1fa22021-04-08 13:18:051767 RTC_DCHECK_RUN_ON(signaling_thread_);
Henrik Boströme88c95e2020-07-08 09:18:501768 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
Steve Anton57858b32018-02-15 23:19:501769
1770 std::map<std::string, std::vector<std::string>> track_ids;
1771
1772 for (const auto& stats : transceiver_stats_infos_) {
Mirko Bonadei739baf02019-01-27 16:29:421773 for (const auto& sender : stats.transceiver->senders()) {
Steve Anton57858b32018-02-15 23:19:501774 std::string track_id =
Henrik Boström15166b22022-10-19 09:06:581775 DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
Henrik Boström8dfc90f2022-09-02 07:39:291776 kDirectionOutbound, sender->internal()->AttachmentId());
Steve Anton57858b32018-02-15 23:19:501777 for (auto& stream_id : sender->stream_ids()) {
1778 track_ids[stream_id].push_back(track_id);
1779 }
1780 }
Mirko Bonadei739baf02019-01-27 16:29:421781 for (const auto& receiver : stats.transceiver->receivers()) {
Steve Anton57858b32018-02-15 23:19:501782 std::string track_id =
Henrik Boström15166b22022-10-19 09:06:581783 DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
Henrik Boström8dfc90f2022-09-02 07:39:291784 kDirectionInbound, receiver->internal()->AttachmentId());
Steve Anton57858b32018-02-15 23:19:501785 for (auto& stream : receiver->streams()) {
Seth Hampson13b8bad2018-03-13 23:05:281786 track_ids[stream->id()].push_back(track_id);
Steve Anton57858b32018-02-15 23:19:501787 }
1788 }
1789 }
1790
1791 // Build stats for each stream ID known.
1792 for (auto& it : track_ids) {
Henrik Boström15166b22022-10-19 09:06:581793 std::unique_ptr<DEPRECATED_RTCMediaStreamStats> stream_stats(
1794 std::make_unique<DEPRECATED_RTCMediaStreamStats>(
1795 "DEPRECATED_S" + it.first, timestamp_us));
Steve Anton57858b32018-02-15 23:19:501796 stream_stats->stream_identifier = it.first;
1797 stream_stats->track_ids = it.second;
1798 report->AddStats(std::move(stream_stats));
1799 }
1800}
1801
1802void RTCStatsCollector::ProduceMediaStreamTrackStats_s(
1803 int64_t timestamp_us,
1804 RTCStatsReport* report) const {
Tomas Gunnarsson67b1fa22021-04-08 13:18:051805 RTC_DCHECK_RUN_ON(signaling_thread_);
Henrik Boströme88c95e2020-07-08 09:18:501806 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1807
Steve Anton57858b32018-02-15 23:19:501808 for (const RtpTransceiverStatsInfo& stats : transceiver_stats_infos_) {
1809 std::vector<rtc::scoped_refptr<RtpSenderInternal>> senders;
Mirko Bonadei739baf02019-01-27 16:29:421810 for (const auto& sender : stats.transceiver->senders()) {
Niels Möllere7cc8832022-01-04 14:20:031811 senders.push_back(
1812 rtc::scoped_refptr<RtpSenderInternal>(sender->internal()));
Steve Anton57858b32018-02-15 23:19:501813 }
Henrik Boströmfc67b452022-07-27 08:55:451814 ProduceSenderMediaTrackStats(timestamp_us, stats.track_media_info_map,
Steve Anton57858b32018-02-15 23:19:501815 senders, report);
1816
1817 std::vector<rtc::scoped_refptr<RtpReceiverInternal>> receivers;
Mirko Bonadei739baf02019-01-27 16:29:421818 for (const auto& receiver : stats.transceiver->receivers()) {
Niels Möllere7cc8832022-01-04 14:20:031819 receivers.push_back(
1820 rtc::scoped_refptr<RtpReceiverInternal>(receiver->internal()));
Steve Anton57858b32018-02-15 23:19:501821 }
Henrik Boströmfc67b452022-07-27 08:55:451822 ProduceReceiverMediaTrackStats(timestamp_us, stats.track_media_info_map,
Steve Anton57858b32018-02-15 23:19:501823 receivers, report);
1824 }
hbos09bc1282016-11-08 14:29:221825}
1826
Henrik Boström646fda02019-05-22 13:49:421827void RTCStatsCollector::ProduceMediaSourceStats_s(
1828 int64_t timestamp_us,
1829 RTCStatsReport* report) const {
Tomas Gunnarsson67b1fa22021-04-08 13:18:051830 RTC_DCHECK_RUN_ON(signaling_thread_);
Henrik Boströme88c95e2020-07-08 09:18:501831 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1832
Henrik Boström646fda02019-05-22 13:49:421833 for (const RtpTransceiverStatsInfo& transceiver_stats_info :
1834 transceiver_stats_infos_) {
1835 const auto& track_media_info_map =
1836 transceiver_stats_info.track_media_info_map;
1837 for (const auto& sender : transceiver_stats_info.transceiver->senders()) {
1838 const auto& sender_internal = sender->internal();
1839 const auto& track = sender_internal->track();
1840 if (!track)
1841 continue;
Henrik Boströmd2c336f2019-07-03 15:11:101842 // TODO(https://crbug.com/webrtc/10771): The same track could be attached
1843 // to multiple senders which should result in multiple senders referencing
1844 // the same media-source stats. When all media source related metrics are
1845 // moved to the track's source (e.g. input frame rate is moved from
1846 // cricket::VideoSenderInfo to VideoTrackSourceInterface::Stats and audio
1847 // levels are moved to the corresponding audio track/source object), don't
1848 // create separate media source stats objects on a per-attachment basis.
Henrik Boström646fda02019-05-22 13:49:421849 std::unique_ptr<RTCMediaSourceStats> media_source_stats;
1850 if (track->kind() == MediaStreamTrackInterface::kAudioKind) {
Taylor Brandstetter64851c02021-06-24 20:32:501851 AudioTrackInterface* audio_track =
1852 static_cast<AudioTrackInterface*>(track.get());
Mirko Bonadei317a1f02019-09-17 15:06:181853 auto audio_source_stats = std::make_unique<RTCAudioSourceStats>(
Henrik Boström646fda02019-05-22 13:49:421854 RTCMediaSourceStatsIDFromKindAndAttachment(
1855 cricket::MEDIA_TYPE_AUDIO, sender_internal->AttachmentId()),
1856 timestamp_us);
Henrik Boströmd2c336f2019-07-03 15:11:101857 // TODO(https://crbug.com/webrtc/10771): We shouldn't need to have an
1858 // SSRC assigned (there shouldn't need to exist a send-stream, created
1859 // by an O/A exchange) in order to read audio media-source stats.
1860 // TODO(https://crbug.com/webrtc/8694): SSRC 0 shouldn't be a magic
1861 // value indicating no SSRC.
1862 if (sender_internal->ssrc() != 0) {
1863 auto* voice_sender_info =
Henrik Boströmfc67b452022-07-27 08:55:451864 track_media_info_map.GetVoiceSenderInfoBySsrc(
Henrik Boströmd2c336f2019-07-03 15:11:101865 sender_internal->ssrc());
1866 if (voice_sender_info) {
1867 audio_source_stats->audio_level = DoubleAudioLevelFromIntAudioLevel(
1868 voice_sender_info->audio_level);
1869 audio_source_stats->total_audio_energy =
1870 voice_sender_info->total_input_energy;
1871 audio_source_stats->total_samples_duration =
1872 voice_sender_info->total_input_duration;
Taylor Brandstetter64851c02021-06-24 20:32:501873 SetAudioProcessingStats(audio_source_stats.get(),
1874 voice_sender_info->apm_statistics);
Henrik Boströmd2c336f2019-07-03 15:11:101875 }
1876 }
Taylor Brandstetter64851c02021-06-24 20:32:501877 // Audio processor may be attached to either the track or the send
1878 // stream, so look in both places.
1879 auto audio_processor(audio_track->GetAudioProcessor());
1880 if (audio_processor.get()) {
Artem Titov880fa812021-07-30 20:30:231881 // The `has_remote_tracks` argument is obsolete; makes no difference
Taylor Brandstetter64851c02021-06-24 20:32:501882 // if it's set to true or false.
1883 AudioProcessorInterface::AudioProcessorStatistics ap_stats =
1884 audio_processor->GetStats(/*has_remote_tracks=*/false);
1885 SetAudioProcessingStats(audio_source_stats.get(),
1886 ap_stats.apm_statistics);
1887 }
Henrik Boströmd2c336f2019-07-03 15:11:101888 media_source_stats = std::move(audio_source_stats);
Henrik Boström646fda02019-05-22 13:49:421889 } else {
1890 RTC_DCHECK_EQ(MediaStreamTrackInterface::kVideoKind, track->kind());
Mirko Bonadei317a1f02019-09-17 15:06:181891 auto video_source_stats = std::make_unique<RTCVideoSourceStats>(
Henrik Boström646fda02019-05-22 13:49:421892 RTCMediaSourceStatsIDFromKindAndAttachment(
1893 cricket::MEDIA_TYPE_VIDEO, sender_internal->AttachmentId()),
1894 timestamp_us);
1895 auto* video_track = static_cast<VideoTrackInterface*>(track.get());
1896 auto* video_source = video_track->GetSource();
1897 VideoTrackSourceInterface::Stats source_stats;
1898 if (video_source && video_source->GetStats(&source_stats)) {
1899 video_source_stats->width = source_stats.input_width;
1900 video_source_stats->height = source_stats.input_height;
1901 }
Henrik Boströmd2c336f2019-07-03 15:11:101902 // TODO(https://crbug.com/webrtc/10771): We shouldn't need to have an
1903 // SSRC assigned (there shouldn't need to exist a send-stream, created
1904 // by an O/A exchange) in order to get framesPerSecond.
1905 // TODO(https://crbug.com/webrtc/8694): SSRC 0 shouldn't be a magic
1906 // value indicating no SSRC.
Henrik Boström646fda02019-05-22 13:49:421907 if (sender_internal->ssrc() != 0) {
Henrik Boströmd2c336f2019-07-03 15:11:101908 auto* video_sender_info =
Henrik Boströmfc67b452022-07-27 08:55:451909 track_media_info_map.GetVideoSenderInfoBySsrc(
Henrik Boströmd2c336f2019-07-03 15:11:101910 sender_internal->ssrc());
1911 if (video_sender_info) {
Henrik Boström646fda02019-05-22 13:49:421912 video_source_stats->frames_per_second =
Henrik Boströmd2c336f2019-07-03 15:11:101913 video_sender_info->framerate_input;
Di Wu668dbf62021-02-27 08:29:151914 video_source_stats->frames = video_sender_info->frames;
Henrik Boström646fda02019-05-22 13:49:421915 }
1916 }
1917 media_source_stats = std::move(video_source_stats);
1918 }
1919 media_source_stats->track_identifier = track->id();
1920 media_source_stats->kind = track->kind();
1921 report->AddStats(std::move(media_source_stats));
1922 }
1923 }
1924}
1925
hbos6ab97ce02016-10-03 21:16:561926void RTCStatsCollector::ProducePeerConnectionStats_s(
Jonas Olssona4d87372019-07-05 17:08:331927 int64_t timestamp_us,
1928 RTCStatsReport* report) const {
Tomas Gunnarsson67b1fa22021-04-08 13:18:051929 RTC_DCHECK_RUN_ON(signaling_thread_);
Henrik Boströme88c95e2020-07-08 09:18:501930 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1931
hbosd565b732016-08-30 21:04:351932 std::unique_ptr<RTCPeerConnectionStats> stats(
Philipp Hanckeb5cf12d2022-09-06 09:55:311933 std::make_unique<RTCPeerConnectionStats>("P", timestamp_us));
hbos82ebe022016-11-14 09:41:091934 stats->data_channels_opened = internal_record_.data_channels_opened;
1935 stats->data_channels_closed = internal_record_.data_channels_closed;
hbos6ab97ce02016-10-03 21:16:561936 report->AddStats(std::move(stats));
hbosd565b732016-08-30 21:04:351937}
1938
hbosdf6075a2016-12-19 12:58:021939void RTCStatsCollector::ProduceRTPStreamStats_n(
Steve Anton593e3252017-12-15 19:44:481940 int64_t timestamp_us,
Steve Anton57858b32018-02-15 23:19:501941 const std::vector<RtpTransceiverStatsInfo>& transceiver_stats_infos,
hbos84abeb12017-01-16 14:16:441942 RTCStatsReport* report) const {
Tomas Gunnarsson67b1fa22021-04-08 13:18:051943 RTC_DCHECK_RUN_ON(network_thread_);
Henrik Boströme88c95e2020-07-08 09:18:501944 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
hbos6ded1902016-11-01 08:50:461945
Steve Anton57858b32018-02-15 23:19:501946 for (const RtpTransceiverStatsInfo& stats : transceiver_stats_infos) {
1947 if (stats.media_type == cricket::MEDIA_TYPE_AUDIO) {
1948 ProduceAudioRTPStreamStats_n(timestamp_us, stats, report);
1949 } else if (stats.media_type == cricket::MEDIA_TYPE_VIDEO) {
1950 ProduceVideoRTPStreamStats_n(timestamp_us, stats, report);
1951 } else {
Artem Titovd3251962021-11-15 15:57:071952 RTC_DCHECK_NOTREACHED();
Guido Urdanetaee2388f2018-02-15 16:36:191953 }
Steve Anton56bae8d2018-02-15 00:07:421954 }
Steve Anton57858b32018-02-15 23:19:501955}
1956
1957void RTCStatsCollector::ProduceAudioRTPStreamStats_n(
1958 int64_t timestamp_us,
1959 const RtpTransceiverStatsInfo& stats,
1960 RTCStatsReport* report) const {
Tomas Gunnarsson67b1fa22021-04-08 13:18:051961 RTC_DCHECK_RUN_ON(network_thread_);
Henrik Boströme88c95e2020-07-08 09:18:501962 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
1963
Steve Anton57858b32018-02-15 23:19:501964 if (!stats.mid || !stats.transport_name) {
1965 return;
1966 }
Henrik Boströmfc67b452022-07-27 08:55:451967 RTC_DCHECK(stats.track_media_info_map.voice_media_info().has_value());
Steve Anton57858b32018-02-15 23:19:501968 std::string mid = *stats.mid;
1969 std::string transport_id = RTCTransportStatsIDFromTransportChannel(
1970 *stats.transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
Alessio Bazzicaf7b1b952021-03-23 16:23:041971 // Inbound and remote-outbound.
1972 // The remote-outbound stats are based on RTCP sender reports sent from the
1973 // remote endpoint providing metrics about the remote outbound streams.
Steve Anton57858b32018-02-15 23:19:501974 for (const cricket::VoiceReceiverInfo& voice_receiver_info :
Henrik Boströmfc67b452022-07-27 08:55:451975 stats.track_media_info_map.voice_media_info()->receivers) {
Steve Anton57858b32018-02-15 23:19:501976 if (!voice_receiver_info.connected())
1977 continue;
Alessio Bazzicaf7b1b952021-03-23 16:23:041978 // Inbound.
Henrik Boströmb2be3922022-09-02 07:37:081979 auto inbound_audio = CreateInboundAudioStreamStats(
1980 stats.track_media_info_map.voice_media_info().value(),
Henrik Boström31c373b2022-09-26 12:56:211981 voice_receiver_info, transport_id, mid, timestamp_us, report);
Steve Anton57858b32018-02-15 23:19:501982 // TODO(hta): This lookup should look for the sender, not the track.
1983 rtc::scoped_refptr<AudioTrackInterface> audio_track =
Henrik Boströmfc67b452022-07-27 08:55:451984 stats.track_media_info_map.GetAudioTrack(voice_receiver_info);
Steve Anton57858b32018-02-15 23:19:501985 if (audio_track) {
1986 inbound_audio->track_id =
Henrik Boström15166b22022-10-19 09:06:581987 DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
Henrik Boström8dfc90f2022-09-02 07:39:291988 kDirectionInbound, stats.track_media_info_map
1989 .GetAttachmentIdByTrack(audio_track.get())
1990 .value());
Henrik Boströma6c7d5c2022-06-16 14:55:311991 inbound_audio->track_identifier = audio_track->id();
hbos6ded1902016-11-01 08:50:461992 }
Henrik Boströmda6297d2022-09-19 09:33:231993 auto* inbound_audio_ptr = report->TryAddStats(std::move(inbound_audio));
1994 if (!inbound_audio_ptr) {
1995 RTC_LOG(LS_ERROR)
1996 << "Unable to add audio 'inbound-rtp' to report, ID is not unique.";
1997 continue;
1998 }
Alessio Bazzicaf7b1b952021-03-23 16:23:041999 // Remote-outbound.
2000 auto remote_outbound_audio = CreateRemoteOutboundAudioStreamStats(
Henrik Boströmda6297d2022-09-19 09:33:232001 voice_receiver_info, mid, *inbound_audio_ptr, transport_id);
Alessio Bazzicaf7b1b952021-03-23 16:23:042002 // Add stats.
2003 if (remote_outbound_audio) {
2004 // When the remote outbound stats are available, the remote ID for the
2005 // local inbound stats is set.
Henrik Boströmda6297d2022-09-19 09:33:232006 auto* remote_outbound_audio_ptr =
2007 report->TryAddStats(std::move(remote_outbound_audio));
2008 if (remote_outbound_audio_ptr) {
2009 inbound_audio_ptr->remote_id = remote_outbound_audio_ptr->id();
2010 } else {
2011 RTC_LOG(LS_ERROR) << "Unable to add audio 'remote-outbound-rtp' to "
2012 << "report, ID is not unique.";
2013 }
Alessio Bazzicaf7b1b952021-03-23 16:23:042014 }
Steve Anton57858b32018-02-15 23:19:502015 }
Alessio Bazzicaf7b1b952021-03-23 16:23:042016 // Outbound.
Henrik Boström4f40fa52019-12-19 12:27:272017 std::map<std::string, RTCOutboundRTPStreamStats*> audio_outbound_rtps;
Steve Anton57858b32018-02-15 23:19:502018 for (const cricket::VoiceSenderInfo& voice_sender_info :
Henrik Boströmfc67b452022-07-27 08:55:452019 stats.track_media_info_map.voice_media_info()->senders) {
Steve Anton57858b32018-02-15 23:19:502020 if (!voice_sender_info.connected())
2021 continue;
Mirko Bonadei317a1f02019-09-17 15:06:182022 auto outbound_audio = std::make_unique<RTCOutboundRTPStreamStats>(
Henrik Boströmb43e3bb2022-09-26 10:36:442023 RTCOutboundRTPStreamStatsIDFromSSRC(
2024 transport_id, cricket::MEDIA_TYPE_AUDIO, voice_sender_info.ssrc()),
Steve Anton57858b32018-02-15 23:19:502025 timestamp_us);
Henrik Boströmb2be3922022-09-02 07:37:082026 SetOutboundRTPStreamStatsFromVoiceSenderInfo(
2027 transport_id, mid,
2028 stats.track_media_info_map.voice_media_info().value(),
Henrik Boström31c373b2022-09-26 12:56:212029 voice_sender_info, outbound_audio.get(), report);
Steve Anton57858b32018-02-15 23:19:502030 rtc::scoped_refptr<AudioTrackInterface> audio_track =
Henrik Boströmfc67b452022-07-27 08:55:452031 stats.track_media_info_map.GetAudioTrack(voice_sender_info);
Steve Anton57858b32018-02-15 23:19:502032 if (audio_track) {
Henrik Boström646fda02019-05-22 13:49:422033 int attachment_id =
Henrik Boströmfc67b452022-07-27 08:55:452034 stats.track_media_info_map.GetAttachmentIdByTrack(audio_track.get())
Niels Möllerafb246b2022-04-20 12:26:502035 .value();
Steve Anton57858b32018-02-15 23:19:502036 outbound_audio->track_id =
Henrik Boström15166b22022-10-19 09:06:582037 DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
Henrik Boström8dfc90f2022-09-02 07:39:292038 kDirectionOutbound, attachment_id);
Henrik Boström646fda02019-05-22 13:49:422039 outbound_audio->media_source_id =
2040 RTCMediaSourceStatsIDFromKindAndAttachment(cricket::MEDIA_TYPE_AUDIO,
2041 attachment_id);
Steve Anton56bae8d2018-02-15 00:07:422042 }
Henrik Boströmda6297d2022-09-19 09:33:232043 auto audio_outbound_pair =
2044 std::make_pair(outbound_audio->id(), outbound_audio.get());
2045 if (report->TryAddStats(std::move(outbound_audio))) {
2046 audio_outbound_rtps.insert(std::move(audio_outbound_pair));
2047 } else {
2048 RTC_LOG(LS_ERROR)
2049 << "Unable to add audio 'outbound-rtp' to report, ID is not unique.";
2050 }
Steve Anton57858b32018-02-15 23:19:502051 }
Alessio Bazzicaf7b1b952021-03-23 16:23:042052 // Remote-inbound.
Henrik Boström883eefc2019-05-27 11:40:252053 // These are Report Block-based, information sent from the remote endpoint,
2054 // providing metrics about our Outbound streams. We take advantage of the fact
2055 // that RTCOutboundRtpStreamStats, RTCCodecStats and RTCTransport have already
2056 // been added to the report.
2057 for (const cricket::VoiceSenderInfo& voice_sender_info :
Henrik Boströmfc67b452022-07-27 08:55:452058 stats.track_media_info_map.voice_media_info()->senders) {
Henrik Boström883eefc2019-05-27 11:40:252059 for (const auto& report_block_data : voice_sender_info.report_block_datas) {
2060 report->AddStats(ProduceRemoteInboundRtpStreamStatsFromReportBlockData(
Henrik Boströmb43e3bb2022-09-26 10:36:442061 transport_id, report_block_data, cricket::MEDIA_TYPE_AUDIO,
2062 audio_outbound_rtps, *report));
Henrik Boström883eefc2019-05-27 11:40:252063 }
2064 }
Steve Anton57858b32018-02-15 23:19:502065}
2066
2067void RTCStatsCollector::ProduceVideoRTPStreamStats_n(
2068 int64_t timestamp_us,
2069 const RtpTransceiverStatsInfo& stats,
2070 RTCStatsReport* report) const {
Tomas Gunnarsson67b1fa22021-04-08 13:18:052071 RTC_DCHECK_RUN_ON(network_thread_);
Henrik Boströme88c95e2020-07-08 09:18:502072 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
2073
Steve Anton57858b32018-02-15 23:19:502074 if (!stats.mid || !stats.transport_name) {
2075 return;
2076 }
Henrik Boströmfc67b452022-07-27 08:55:452077 RTC_DCHECK(stats.track_media_info_map.video_media_info().has_value());
Steve Anton57858b32018-02-15 23:19:502078 std::string mid = *stats.mid;
2079 std::string transport_id = RTCTransportStatsIDFromTransportChannel(
2080 *stats.transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
2081 // Inbound
2082 for (const cricket::VideoReceiverInfo& video_receiver_info :
Henrik Boströmfc67b452022-07-27 08:55:452083 stats.track_media_info_map.video_media_info()->receivers) {
Steve Anton57858b32018-02-15 23:19:502084 if (!video_receiver_info.connected())
2085 continue;
Mirko Bonadei317a1f02019-09-17 15:06:182086 auto inbound_video = std::make_unique<RTCInboundRTPStreamStats>(
Henrik Boströmb43e3bb2022-09-26 10:36:442087 RTCInboundRTPStreamStatsIDFromSSRC(transport_id,
2088 cricket::MEDIA_TYPE_VIDEO,
Alessio Bazzicaf7b1b952021-03-23 16:23:042089 video_receiver_info.ssrc()),
Steve Anton57858b32018-02-15 23:19:502090 timestamp_us);
Henrik Boströmb2be3922022-09-02 07:37:082091 SetInboundRTPStreamStatsFromVideoReceiverInfo(
2092 transport_id, mid,
2093 stats.track_media_info_map.video_media_info().value(),
Henrik Boström31c373b2022-09-26 12:56:212094 video_receiver_info, inbound_video.get(), report);
Steve Anton57858b32018-02-15 23:19:502095 rtc::scoped_refptr<VideoTrackInterface> video_track =
Henrik Boströmfc67b452022-07-27 08:55:452096 stats.track_media_info_map.GetVideoTrack(video_receiver_info);
Steve Anton57858b32018-02-15 23:19:502097 if (video_track) {
2098 inbound_video->track_id =
Henrik Boström15166b22022-10-19 09:06:582099 DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
Henrik Boström8dfc90f2022-09-02 07:39:292100 kDirectionInbound, stats.track_media_info_map
2101 .GetAttachmentIdByTrack(video_track.get())
2102 .value());
Henrik Boströma6c7d5c2022-06-16 14:55:312103 inbound_video->track_identifier = video_track->id();
Steve Anton57858b32018-02-15 23:19:502104 }
Henrik Boströmda6297d2022-09-19 09:33:232105 if (!report->TryAddStats(std::move(inbound_video))) {
2106 RTC_LOG(LS_ERROR)
2107 << "Unable to add video 'inbound-rtp' to report, ID is not unique.";
2108 }
Steve Anton57858b32018-02-15 23:19:502109 }
2110 // Outbound
Henrik Boström4f40fa52019-12-19 12:27:272111 std::map<std::string, RTCOutboundRTPStreamStats*> video_outbound_rtps;
Steve Anton57858b32018-02-15 23:19:502112 for (const cricket::VideoSenderInfo& video_sender_info :
Henrik Boströmfc67b452022-07-27 08:55:452113 stats.track_media_info_map.video_media_info()->senders) {
Steve Anton57858b32018-02-15 23:19:502114 if (!video_sender_info.connected())
2115 continue;
Mirko Bonadei317a1f02019-09-17 15:06:182116 auto outbound_video = std::make_unique<RTCOutboundRTPStreamStats>(
Henrik Boströmb43e3bb2022-09-26 10:36:442117 RTCOutboundRTPStreamStatsIDFromSSRC(
2118 transport_id, cricket::MEDIA_TYPE_VIDEO, video_sender_info.ssrc()),
Steve Anton57858b32018-02-15 23:19:502119 timestamp_us);
Henrik Boströmb2be3922022-09-02 07:37:082120 SetOutboundRTPStreamStatsFromVideoSenderInfo(
2121 transport_id, mid,
2122 stats.track_media_info_map.video_media_info().value(),
Henrik Boström31c373b2022-09-26 12:56:212123 video_sender_info, outbound_video.get(), report);
Steve Anton57858b32018-02-15 23:19:502124 rtc::scoped_refptr<VideoTrackInterface> video_track =
Henrik Boströmfc67b452022-07-27 08:55:452125 stats.track_media_info_map.GetVideoTrack(video_sender_info);
Steve Anton57858b32018-02-15 23:19:502126 if (video_track) {
Henrik Boström646fda02019-05-22 13:49:422127 int attachment_id =
Henrik Boströmfc67b452022-07-27 08:55:452128 stats.track_media_info_map.GetAttachmentIdByTrack(video_track.get())
Niels Möllerafb246b2022-04-20 12:26:502129 .value();
Steve Anton57858b32018-02-15 23:19:502130 outbound_video->track_id =
Henrik Boström15166b22022-10-19 09:06:582131 DEPRECATED_RTCMediaStreamTrackStatsIDFromDirectionAndAttachment(
Henrik Boström8dfc90f2022-09-02 07:39:292132 kDirectionOutbound, attachment_id);
Henrik Boström646fda02019-05-22 13:49:422133 outbound_video->media_source_id =
2134 RTCMediaSourceStatsIDFromKindAndAttachment(cricket::MEDIA_TYPE_VIDEO,
2135 attachment_id);
Steve Anton57858b32018-02-15 23:19:502136 }
Henrik Boströmda6297d2022-09-19 09:33:232137 auto video_outbound_pair =
2138 std::make_pair(outbound_video->id(), outbound_video.get());
2139 if (report->TryAddStats(std::move(outbound_video))) {
2140 video_outbound_rtps.insert(std::move(video_outbound_pair));
2141 } else {
2142 RTC_LOG(LS_ERROR)
2143 << "Unable to add video 'outbound-rtp' to report, ID is not unique.";
2144 }
hbos6ded1902016-11-01 08:50:462145 }
Henrik Boström883eefc2019-05-27 11:40:252146 // Remote-inbound
2147 // These are Report Block-based, information sent from the remote endpoint,
2148 // providing metrics about our Outbound streams. We take advantage of the fact
2149 // that RTCOutboundRtpStreamStats, RTCCodecStats and RTCTransport have already
2150 // been added to the report.
2151 for (const cricket::VideoSenderInfo& video_sender_info :
Henrik Boströmfc67b452022-07-27 08:55:452152 stats.track_media_info_map.video_media_info()->senders) {
Henrik Boström883eefc2019-05-27 11:40:252153 for (const auto& report_block_data : video_sender_info.report_block_datas) {
2154 report->AddStats(ProduceRemoteInboundRtpStreamStatsFromReportBlockData(
Henrik Boströmb43e3bb2022-09-26 10:36:442155 transport_id, report_block_data, cricket::MEDIA_TYPE_VIDEO,
2156 video_outbound_rtps, *report));
Henrik Boström883eefc2019-05-27 11:40:252157 }
2158 }
hbos6ded1902016-11-01 08:50:462159}
2160
hbosdf6075a2016-12-19 12:58:022161void RTCStatsCollector::ProduceTransportStats_n(
Steve Anton5dfde182018-02-06 18:34:402162 int64_t timestamp_us,
2163 const std::map<std::string, cricket::TransportStats>&
2164 transport_stats_by_name,
hbos2fa7c672016-10-24 11:00:052165 const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
2166 RTCStatsReport* report) const {
Tomas Gunnarsson67b1fa22021-04-08 13:18:052167 RTC_DCHECK_RUN_ON(network_thread_);
Henrik Boströme88c95e2020-07-08 09:18:502168 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
2169
Steve Anton5dfde182018-02-06 18:34:402170 for (const auto& entry : transport_stats_by_name) {
2171 const std::string& transport_name = entry.first;
2172 const cricket::TransportStats& transport_stats = entry.second;
2173
hbos2fa7c672016-10-24 11:00:052174 // Get reference to RTCP channel, if it exists.
2175 std::string rtcp_transport_stats_id;
Steve Anton5dfde182018-02-06 18:34:402176 for (const cricket::TransportChannelStats& channel_stats :
2177 transport_stats.channel_stats) {
Jonas Olssona4d87372019-07-05 17:08:332178 if (channel_stats.component == cricket::ICE_CANDIDATE_COMPONENT_RTCP) {
hbos2fa7c672016-10-24 11:00:052179 rtcp_transport_stats_id = RTCTransportStatsIDFromTransportChannel(
Steve Anton5dfde182018-02-06 18:34:402180 transport_name, channel_stats.component);
hbos2fa7c672016-10-24 11:00:052181 break;
2182 }
2183 }
2184
2185 // Get reference to local and remote certificates of this transport, if they
2186 // exist.
Steve Anton5dfde182018-02-06 18:34:402187 const auto& certificate_stats_it =
2188 transport_cert_stats.find(transport_name);
hbos2fa7c672016-10-24 11:00:052189 RTC_DCHECK(certificate_stats_it != transport_cert_stats.cend());
2190 std::string local_certificate_id;
2191 if (certificate_stats_it->second.local) {
2192 local_certificate_id = RTCCertificateIDFromFingerprint(
2193 certificate_stats_it->second.local->fingerprint);
2194 }
2195 std::string remote_certificate_id;
2196 if (certificate_stats_it->second.remote) {
2197 remote_certificate_id = RTCCertificateIDFromFingerprint(
2198 certificate_stats_it->second.remote->fingerprint);
2199 }
2200
2201 // There is one transport stats for each channel.
Steve Anton5dfde182018-02-06 18:34:402202 for (const cricket::TransportChannelStats& channel_stats :
2203 transport_stats.channel_stats) {
hbos2fa7c672016-10-24 11:00:052204 std::unique_ptr<RTCTransportStats> transport_stats(
Philipp Hanckeb5cf12d2022-09-06 09:55:312205 std::make_unique<RTCTransportStats>(
2206 RTCTransportStatsIDFromTransportChannel(transport_name,
2207 channel_stats.component),
2208 timestamp_us));
Jonas Oreland42da5a92022-03-01 12:55:372209 transport_stats->packets_sent =
2210 channel_stats.ice_transport_stats.packets_sent;
2211 transport_stats->packets_received =
2212 channel_stats.ice_transport_stats.packets_received;
2213 transport_stats->bytes_sent =
2214 channel_stats.ice_transport_stats.bytes_sent;
2215 transport_stats->bytes_received =
2216 channel_stats.ice_transport_stats.bytes_received;
Jonas Olssona4d87372019-07-05 17:08:332217 transport_stats->dtls_state =
2218 DtlsTransportStateToRTCDtlsTransportState(channel_stats.dtls_state);
Jonas Oreland149dc722019-08-28 06:10:272219 transport_stats->selected_candidate_pair_changes =
2220 channel_stats.ice_transport_stats.selected_candidate_pair_changes;
Philipp Hanckecc1b9b02022-05-04 16:58:262221 transport_stats->ice_role =
2222 IceRoleToRTCIceRole(channel_stats.ice_transport_stats.ice_role);
Philipp Hancke95b1a342022-05-05 05:53:542223 transport_stats->ice_local_username_fragment =
2224 channel_stats.ice_transport_stats.ice_local_username_fragment;
Philipp Hancke1f491572022-05-09 15:43:312225 transport_stats->ice_state = IceTransportStateToRTCIceTransportState(
2226 channel_stats.ice_transport_stats.ice_state);
hbos2fa7c672016-10-24 11:00:052227 for (const cricket::ConnectionInfo& info :
Jonas Oreland149dc722019-08-28 06:10:272228 channel_stats.ice_transport_stats.connection_infos) {
hbos2fa7c672016-10-24 11:00:052229 if (info.best_connection) {
hbos2fa7c672016-10-24 11:00:052230 transport_stats->selected_candidate_pair_id =
2231 RTCIceCandidatePairStatsIDFromConnectionInfo(info);
2232 }
2233 }
2234 if (channel_stats.component != cricket::ICE_CANDIDATE_COMPONENT_RTCP &&
2235 !rtcp_transport_stats_id.empty()) {
2236 transport_stats->rtcp_transport_stats_id = rtcp_transport_stats_id;
2237 }
2238 if (!local_certificate_id.empty())
2239 transport_stats->local_certificate_id = local_certificate_id;
2240 if (!remote_certificate_id.empty())
2241 transport_stats->remote_certificate_id = remote_certificate_id;
Harald Alvestrand5cb78072019-10-28 08:51:172242 // Crypto information
2243 if (channel_stats.ssl_version_bytes) {
2244 char bytes[5];
2245 snprintf(bytes, sizeof(bytes), "%04X", channel_stats.ssl_version_bytes);
2246 transport_stats->tls_version = bytes;
2247 }
Philipp Hancke69c1df22022-04-22 13:46:242248
2249 if (channel_stats.dtls_role) {
2250 transport_stats->dtls_role = *channel_stats.dtls_role == rtc::SSL_CLIENT
2251 ? webrtc::RTCDtlsRole::kClient
2252 : webrtc::RTCDtlsRole::kServer;
2253 } else {
2254 transport_stats->dtls_role = webrtc::RTCDtlsRole::kUnknown;
2255 }
2256
Mirko Bonadei7750d802021-07-26 15:27:422257 if (channel_stats.ssl_cipher_suite != rtc::kTlsNullWithNullNull &&
Harald Alvestrand5cb78072019-10-28 08:51:172258 rtc::SSLStreamAdapter::SslCipherSuiteToName(
2259 channel_stats.ssl_cipher_suite)
2260 .length()) {
2261 transport_stats->dtls_cipher =
2262 rtc::SSLStreamAdapter::SslCipherSuiteToName(
2263 channel_stats.ssl_cipher_suite);
2264 }
Mirko Bonadei7750d802021-07-26 15:27:422265 if (channel_stats.srtp_crypto_suite != rtc::kSrtpInvalidCryptoSuite &&
Harald Alvestrand5cb78072019-10-28 08:51:172266 rtc::SrtpCryptoSuiteToName(channel_stats.srtp_crypto_suite)
2267 .length()) {
2268 transport_stats->srtp_cipher =
2269 rtc::SrtpCryptoSuiteToName(channel_stats.srtp_crypto_suite);
2270 }
hbos2fa7c672016-10-24 11:00:052271 report->AddStats(std::move(transport_stats));
2272 }
2273 }
2274}
2275
2276std::map<std::string, RTCStatsCollector::CertificateStatsPair>
hbosdf6075a2016-12-19 12:58:022277RTCStatsCollector::PrepareTransportCertificateStats_n(
Steve Anton5dfde182018-02-06 18:34:402278 const std::map<std::string, cricket::TransportStats>&
Henrik Boström69d23c92022-09-26 12:13:172279 transport_stats_by_name) {
Tomas Gunnarsson67b1fa22021-04-08 13:18:052280 RTC_DCHECK_RUN_ON(network_thread_);
Henrik Boströme88c95e2020-07-08 09:18:502281 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
2282
hbos2fa7c672016-10-24 11:00:052283 std::map<std::string, CertificateStatsPair> transport_cert_stats;
Henrik Boströmb3dd1732022-09-30 15:22:442284 {
2285 MutexLock lock(&cached_certificates_mutex_);
Henrik Boström69d23c92022-09-26 12:13:172286 // Copy the certificate info from the cache, avoiding expensive
2287 // rtc::SSLCertChain::GetStats() calls.
2288 for (const auto& pair : cached_certificates_by_transport_) {
2289 transport_cert_stats.insert(
2290 std::make_pair(pair.first, pair.second.Copy()));
hbos2fa7c672016-10-24 11:00:052291 }
Henrik Boströmb3dd1732022-09-30 15:22:442292 }
2293 if (transport_cert_stats.empty()) {
Henrik Boström69d23c92022-09-26 12:13:172294 // Collect certificate info.
2295 for (const auto& entry : transport_stats_by_name) {
2296 const std::string& transport_name = entry.first;
Steve Anton5dfde182018-02-06 18:34:402297
Henrik Boström69d23c92022-09-26 12:13:172298 CertificateStatsPair certificate_stats_pair;
2299 rtc::scoped_refptr<rtc::RTCCertificate> local_certificate;
2300 if (pc_->GetLocalCertificate(transport_name, &local_certificate)) {
2301 certificate_stats_pair.local =
2302 local_certificate->GetSSLCertificateChain().GetStats();
2303 }
2304
2305 std::unique_ptr<rtc::SSLCertChain> remote_cert_chain =
2306 pc_->GetRemoteSSLCertChain(transport_name);
2307 if (remote_cert_chain) {
2308 certificate_stats_pair.remote = remote_cert_chain->GetStats();
2309 }
2310
2311 transport_cert_stats.insert(
2312 std::make_pair(transport_name, std::move(certificate_stats_pair)));
hbos2fa7c672016-10-24 11:00:052313 }
Henrik Boström69d23c92022-09-26 12:13:172314 // Copy the result into the certificate cache for future reference.
Henrik Boströmb3dd1732022-09-30 15:22:442315 MutexLock lock(&cached_certificates_mutex_);
Henrik Boström69d23c92022-09-26 12:13:172316 for (const auto& pair : transport_cert_stats) {
2317 cached_certificates_by_transport_.insert(
2318 std::make_pair(pair.first, pair.second.Copy()));
2319 }
hbos2fa7c672016-10-24 11:00:052320 }
2321 return transport_cert_stats;
2322}
2323
Tomas Gunnarssonbfd9ba82021-04-18 09:55:572324void RTCStatsCollector::PrepareTransceiverStatsInfosAndCallStats_s_w_n() {
Tomas Gunnarsson67b1fa22021-04-08 13:18:052325 RTC_DCHECK_RUN_ON(signaling_thread_);
Steve Anton56bae8d2018-02-15 00:07:422326
Henrik Boström180faeb2020-11-13 08:05:212327 transceiver_stats_infos_.clear();
Steve Anton57858b32018-02-15 23:19:502328 // These are used to invoke GetStats for all the media channels together in
2329 // one worker thread hop.
Henrik Boströmfc67b452022-07-27 08:55:452330 std::map<cricket::VoiceMediaChannel*, cricket::VoiceMediaInfo> voice_stats;
2331 std::map<cricket::VideoMediaChannel*, cricket::VideoMediaInfo> video_stats;
Steve Anton57858b32018-02-15 23:19:502332
Tomas Gunnarssonbfd9ba82021-04-18 09:55:572333 auto transceivers = pc_->GetTransceiversInternal();
2334
2335 // TODO(tommi): See if we can avoid synchronously blocking the signaling
Danil Chapovalov9e09a1f2022-09-08 16:38:102336 // thread while we do this (or avoid the BlockingCall at all).
2337 network_thread_->BlockingCall([this, &transceivers, &voice_stats,
2338 &video_stats] {
Henrik Boströme88c95e2020-07-08 09:18:502339 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
Steve Anton57858b32018-02-15 23:19:502340
Tomas Gunnarssonbfd9ba82021-04-18 09:55:572341 for (const auto& transceiver_proxy : transceivers) {
2342 RtpTransceiver* transceiver = transceiver_proxy->internal();
Henrik Boströme88c95e2020-07-08 09:18:502343 cricket::MediaType media_type = transceiver->media_type();
Steve Anton57858b32018-02-15 23:19:502344
Henrik Boströme88c95e2020-07-08 09:18:502345 // Prepare stats entry. The TrackMediaInfoMap will be filled in after the
2346 // stats have been fetched on the worker thread.
Henrik Boström180faeb2020-11-13 08:05:212347 transceiver_stats_infos_.emplace_back();
2348 RtpTransceiverStatsInfo& stats = transceiver_stats_infos_.back();
Tomas Gunnarssonbfd9ba82021-04-18 09:55:572349 stats.transceiver = transceiver;
Henrik Boströme88c95e2020-07-08 09:18:502350 stats.media_type = media_type;
Steve Anton57858b32018-02-15 23:19:502351
Tomas Gunnarssonbfd9ba82021-04-18 09:55:572352 cricket::ChannelInterface* channel = transceiver->channel();
Henrik Boströme88c95e2020-07-08 09:18:502353 if (!channel) {
2354 // The remaining fields require a BaseChannel.
2355 continue;
2356 }
Steve Anton57858b32018-02-15 23:19:502357
Tomas Gunnarsson5411b172022-01-24 07:45:262358 stats.mid = channel->mid();
Tomas Gunnarsson94f01942022-01-03 14:59:122359 stats.transport_name = std::string(channel->transport_name());
Henrik Boströme88c95e2020-07-08 09:18:502360
2361 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
Henrik Boströmfc67b452022-07-27 08:55:452362 cricket::VoiceMediaChannel* voice_channel =
2363 static_cast<cricket::VoiceMediaChannel*>(channel->media_channel());
2364 RTC_DCHECK(voice_stats.find(voice_channel) == voice_stats.end());
2365 voice_stats.insert(
2366 std::make_pair(voice_channel, cricket::VoiceMediaInfo()));
Henrik Boströme88c95e2020-07-08 09:18:502367 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
Henrik Boströmfc67b452022-07-27 08:55:452368 cricket::VideoMediaChannel* video_channel =
2369 static_cast<cricket::VideoMediaChannel*>(channel->media_channel());
2370 RTC_DCHECK(video_stats.find(video_channel) == video_stats.end());
2371 video_stats.insert(
2372 std::make_pair(video_channel, cricket::VideoMediaInfo()));
Henrik Boströme88c95e2020-07-08 09:18:502373 } else {
Artem Titovd3251962021-11-15 15:57:072374 RTC_DCHECK_NOTREACHED();
Henrik Boströme88c95e2020-07-08 09:18:502375 }
Steve Anton57858b32018-02-15 23:19:502376 }
Tomas Gunnarssonbfd9ba82021-04-18 09:55:572377 });
Steve Anton57858b32018-02-15 23:19:502378
Henrik Boström180faeb2020-11-13 08:05:212379 // We jump to the worker thread and call GetStats() on each media channel as
2380 // well as GetCallStats(). At the same time we construct the
2381 // TrackMediaInfoMaps, which also needs info from the worker thread. This
2382 // minimizes the number of thread jumps.
Danil Chapovalov9e09a1f2022-09-08 16:38:102383 worker_thread_->BlockingCall([&] {
Henrik Boström6fafbe32020-07-08 08:37:002384 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
2385
Henrik Boströmfc67b452022-07-27 08:55:452386 for (auto& pair : voice_stats) {
2387 if (!pair.first->GetStats(&pair.second,
2388 /*get_and_clear_legacy_stats=*/false)) {
Steve Anton57858b32018-02-15 23:19:502389 RTC_LOG(LS_WARNING) << "Failed to get voice stats.";
2390 }
2391 }
Henrik Boströmfc67b452022-07-27 08:55:452392 for (auto& pair : video_stats) {
2393 if (!pair.first->GetStats(&pair.second)) {
Steve Anton57858b32018-02-15 23:19:502394 RTC_LOG(LS_WARNING) << "Failed to get video stats.";
2395 }
2396 }
Steve Anton57858b32018-02-15 23:19:502397
Henrik Boström6fafbe32020-07-08 08:37:002398 // Create the TrackMediaInfoMap for each transceiver stats object.
Henrik Boström180faeb2020-11-13 08:05:212399 for (auto& stats : transceiver_stats_infos_) {
Henrik Boström6fafbe32020-07-08 08:37:002400 auto transceiver = stats.transceiver;
Henrik Boströmfc67b452022-07-27 08:55:452401 absl::optional<cricket::VoiceMediaInfo> voice_media_info;
2402 absl::optional<cricket::VideoMediaInfo> video_media_info;
Harald Alvestranda4e94802022-04-30 16:09:522403 auto channel = transceiver->channel();
2404 if (channel) {
Henrik Boström6fafbe32020-07-08 08:37:002405 cricket::MediaType media_type = transceiver->media_type();
2406 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
Henrik Boströmfc67b452022-07-27 08:55:452407 cricket::VoiceMediaChannel* voice_channel =
2408 static_cast<cricket::VoiceMediaChannel*>(
2409 channel->media_channel());
2410 RTC_DCHECK(voice_stats.find(voice_channel) != voice_stats.end());
2411 voice_media_info = std::move(voice_stats[voice_channel]);
Henrik Boström6fafbe32020-07-08 08:37:002412 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
Henrik Boströmfc67b452022-07-27 08:55:452413 cricket::VideoMediaChannel* video_channel =
2414 static_cast<cricket::VideoMediaChannel*>(
2415 channel->media_channel());
2416 RTC_DCHECK(video_stats.find(video_channel) != video_stats.end());
2417 video_media_info = std::move(video_stats[video_channel]);
Henrik Boström6fafbe32020-07-08 08:37:002418 }
Steve Anton57858b32018-02-15 23:19:502419 }
Henrik Boström6fafbe32020-07-08 08:37:002420 std::vector<rtc::scoped_refptr<RtpSenderInternal>> senders;
2421 for (const auto& sender : transceiver->senders()) {
Niels Möllere7cc8832022-01-04 14:20:032422 senders.push_back(
2423 rtc::scoped_refptr<RtpSenderInternal>(sender->internal()));
Henrik Boström6fafbe32020-07-08 08:37:002424 }
2425 std::vector<rtc::scoped_refptr<RtpReceiverInternal>> receivers;
2426 for (const auto& receiver : transceiver->receivers()) {
Niels Möllere7cc8832022-01-04 14:20:032427 receivers.push_back(
2428 rtc::scoped_refptr<RtpReceiverInternal>(receiver->internal()));
Henrik Boström6fafbe32020-07-08 08:37:002429 }
Henrik Boströmfc67b452022-07-27 08:55:452430 stats.track_media_info_map.Initialize(std::move(voice_media_info),
2431 std::move(video_media_info),
2432 senders, receivers);
Steve Anton57858b32018-02-15 23:19:502433 }
Steve Anton57858b32018-02-15 23:19:502434
Henrik Boström180faeb2020-11-13 08:05:212435 call_stats_ = pc_->GetCallStats();
2436 });
hbos0adb8282016-11-23 10:32:062437}
2438
Taylor Brandstetter3a034e12020-07-09 22:32:342439void RTCStatsCollector::OnSctpDataChannelCreated(SctpDataChannel* channel) {
2440 channel->SignalOpened.connect(this, &RTCStatsCollector::OnDataChannelOpened);
2441 channel->SignalClosed.connect(this, &RTCStatsCollector::OnDataChannelClosed);
2442}
2443
2444void RTCStatsCollector::OnDataChannelOpened(DataChannelInterface* channel) {
Tomas Gunnarsson67b1fa22021-04-08 13:18:052445 RTC_DCHECK_RUN_ON(signaling_thread_);
Jonas Olssona4d87372019-07-05 17:08:332446 bool result = internal_record_.opened_data_channels
2447 .insert(reinterpret_cast<uintptr_t>(channel))
2448 .second;
hbos82ebe022016-11-14 09:41:092449 ++internal_record_.data_channels_opened;
2450 RTC_DCHECK(result);
2451}
2452
Taylor Brandstetter3a034e12020-07-09 22:32:342453void RTCStatsCollector::OnDataChannelClosed(DataChannelInterface* channel) {
Tomas Gunnarsson67b1fa22021-04-08 13:18:052454 RTC_DCHECK_RUN_ON(signaling_thread_);
hbos82ebe022016-11-14 09:41:092455 // Only channels that have been fully opened (and have increased the
Artem Titov880fa812021-07-30 20:30:232456 // `data_channels_opened_` counter) increase the closed counter.
hbos5bf9def2017-03-20 10:14:142457 if (internal_record_.opened_data_channels.erase(
2458 reinterpret_cast<uintptr_t>(channel))) {
hbos82ebe022016-11-14 09:41:092459 ++internal_record_.data_channels_closed;
2460 }
2461}
2462
hboscc555c52016-10-18 19:48:312463const char* CandidateTypeToRTCIceCandidateTypeForTesting(
2464 const std::string& type) {
2465 return CandidateTypeToRTCIceCandidateType(type);
2466}
2467
2468const char* DataStateToRTCDataChannelStateForTesting(
2469 DataChannelInterface::DataState state) {
2470 return DataStateToRTCDataChannelState(state);
2471}
2472
hbosd565b732016-08-30 21:04:352473} // namespace webrtc