blob: 055be6fe99c1391822029f1e45856600d403dcf1 [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
Jonas Olssona4d87372019-07-05 17:08:3311#include "pc/rtc_stats_collector.h"
12
Harald Alvestrandc24a2182022-02-23 13:44:5913#include <stddef.h>
14#include <stdint.h>
Henrik Boström883eefc2019-05-27 11:40:2515
16#include <algorithm>
hbos9e302742017-01-20 10:47:1017#include <initializer_list>
hbosd565b732016-08-30 21:04:3518#include <memory>
hbosda389e32016-10-25 17:55:0819#include <ostream>
hbosd565b732016-08-30 21:04:3520#include <string>
Harald Alvestrandc24a2182022-02-23 13:44:5921#include <type_traits>
Steve Anton36b29d12017-10-30 16:57:4222#include <utility>
hbosd565b732016-08-30 21:04:3523#include <vector>
24
Steve Anton1c9c9fc2019-02-14 23:13:0925#include "absl/strings/str_replace.h"
Harald Alvestrandc24a2182022-02-23 13:44:5926#include "api/candidate.h"
Mirko Bonadei9f6808b2021-05-21 18:46:0927#include "api/dtls_transport_interface.h"
Harald Alvestrandc24a2182022-02-23 13:44:5928#include "api/media_stream_interface.h"
Harald Alvestrand9cb42c82020-10-11 13:03:4729#include "api/media_stream_track.h"
Steve Anton10542f22019-01-11 17:11:0030#include "api/rtp_parameters.h"
Fredrik Hernqvist828de802023-01-19 14:04:5431#include "api/rtp_transceiver_direction.h"
Harald Alvestrandc24a2182022-02-23 13:44:5932#include "api/stats/rtc_stats.h"
Steve Anton10542f22019-01-11 17:11:0033#include "api/stats/rtc_stats_report.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3134#include "api/stats/rtcstats_objects.h"
Sebastian Jansson5f83cf02018-05-08 12:52:2235#include "api/units/time_delta.h"
Harald Alvestrandc24a2182022-02-23 13:44:5936#include "api/units/timestamp.h"
37#include "api/video/recordable_encoded_frame.h"
38#include "api/video/video_content_type.h"
39#include "api/video/video_frame.h"
40#include "api/video/video_sink_interface.h"
41#include "api/video/video_source_interface.h"
Henrik Boströmc5f8f802022-10-19 15:50:0942#include "api/video/video_timing.h"
Evan Shrubsole9b235cd2022-12-06 10:09:1043#include "api/video_codecs/scalability_mode.h"
Harald Alvestrandc24a2182022-02-23 13:44:5944#include "common_video/include/quality_limitation_reason.h"
45#include "media/base/media_channel.h"
Fredrik Hernqvistefbe7532023-01-13 15:42:3646#include "modules/audio_device/include/audio_device.h"
Harald Alvestrandc24a2182022-02-23 13:44:5947#include "modules/audio_processing/include/audio_processing_statistics.h"
Henrik Boström883eefc2019-05-27 11:40:2548#include "modules/rtp_rtcp/include/report_block_data.h"
49#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
Harald Alvestrandc24a2182022-02-23 13:44:5950#include "p2p/base/connection_info.h"
51#include "p2p/base/ice_transport_internal.h"
Steve Anton10542f22019-01-11 17:11:0052#include "p2p/base/p2p_constants.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3153#include "p2p/base/port.h"
Steve Anton10542f22019-01-11 17:11:0054#include "pc/media_stream.h"
Harald Alvestrandc24a2182022-02-23 13:44:5955#include "pc/stream_collection.h"
Harald Alvestrand9e5aeb92022-05-11 09:35:3656#include "pc/test/fake_data_channel_controller.h"
Steve Anton10542f22019-01-11 17:11:0057#include "pc/test/fake_peer_connection_for_stats.h"
58#include "pc/test/mock_data_channel.h"
59#include "pc/test/mock_rtp_receiver_internal.h"
60#include "pc/test/mock_rtp_sender_internal.h"
61#include "pc/test/rtc_stats_obtainer.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3162#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 17:11:0063#include "rtc_base/fake_clock.h"
64#include "rtc_base/fake_ssl_identity.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3165#include "rtc_base/gunit.h"
Harald Alvestrandc24a2182022-02-23 13:44:5966#include "rtc_base/network_constants.h"
67#include "rtc_base/ref_counted_object.h"
68#include "rtc_base/rtc_certificate.h"
69#include "rtc_base/socket_address.h"
70#include "rtc_base/ssl_fingerprint.h"
71#include "rtc_base/ssl_identity.h"
72#include "rtc_base/ssl_stream_adapter.h"
73#include "rtc_base/string_encode.h"
Harald Alvestrand910cdc22020-01-09 11:58:2374#include "rtc_base/strings/json.h"
Markus Handell6fcd0f82020-07-07 17:08:5375#include "rtc_base/synchronization/mutex.h"
Steve Anton10542f22019-01-11 17:11:0076#include "rtc_base/time_utils.h"
Harald Alvestrandc24a2182022-02-23 13:44:5977#include "test/gmock.h"
78#include "test/gtest.h"
hbosd565b732016-08-30 21:04:3579
Alessio Bazzica049e6112021-03-18 11:55:1180using ::testing::_;
Mirko Bonadei6a489f22019-04-09 13:11:1281using ::testing::AtLeast;
82using ::testing::Invoke;
83using ::testing::Return;
hbosd565b732016-08-30 21:04:3584
85namespace webrtc {
86
Artem Titov880fa812021-07-30 20:30:2387// These are used by gtest code, such as if `EXPECT_EQ` fails.
hbosda389e32016-10-25 17:55:0888void PrintTo(const RTCCertificateStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:1289 *os << stats.ToJson();
hbosda389e32016-10-25 17:55:0890}
91
hbos0adb8282016-11-23 10:32:0692void PrintTo(const RTCCodecStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:1293 *os << stats.ToJson();
hbos0adb8282016-11-23 10:32:0694}
95
hbosda389e32016-10-25 17:55:0896void PrintTo(const RTCDataChannelStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:1297 *os << stats.ToJson();
hbosda389e32016-10-25 17:55:0898}
99
100void PrintTo(const RTCIceCandidatePairStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:12101 *os << stats.ToJson();
hbosda389e32016-10-25 17:55:08102}
103
104void PrintTo(const RTCLocalIceCandidateStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:12105 *os << stats.ToJson();
hbosda389e32016-10-25 17:55:08106}
107
108void PrintTo(const RTCRemoteIceCandidateStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:12109 *os << stats.ToJson();
hbosda389e32016-10-25 17:55:08110}
111
112void PrintTo(const RTCPeerConnectionStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:12113 *os << stats.ToJson();
hbosda389e32016-10-25 17:55:08114}
115
Philipp Hancke1f98b462023-03-07 08:53:59116void PrintTo(const RTCInboundRtpStreamStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:12117 *os << stats.ToJson();
hboseeafe942016-11-01 10:00:17118}
119
Philipp Hancke1f98b462023-03-07 08:53:59120void PrintTo(const RTCOutboundRtpStreamStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:12121 *os << stats.ToJson();
hbos6ded1902016-11-01 08:50:46122}
123
Henrik Boström883eefc2019-05-27 11:40:25124void PrintTo(const RTCRemoteInboundRtpStreamStats& stats, ::std::ostream* os) {
125 *os << stats.ToJson();
126}
127
Henrik Boström646fda02019-05-22 13:49:42128void PrintTo(const RTCAudioSourceStats& stats, ::std::ostream* os) {
129 *os << stats.ToJson();
130}
131
132void PrintTo(const RTCVideoSourceStats& stats, ::std::ostream* os) {
133 *os << stats.ToJson();
134}
135
hbosda389e32016-10-25 17:55:08136void PrintTo(const RTCTransportStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:12137 *os << stats.ToJson();
hbosda389e32016-10-25 17:55:08138}
139
hbosc82f2e12016-09-05 08:36:50140namespace {
141
142const int64_t kGetStatsReportTimeoutMs = 1000;
143
Alessio Bazzicaf7b1b952021-03-23 16:23:04144// Fake data used by `SetupExampleStatsVoiceGraph()` to fill in remote outbound
145// stats.
146constexpr int64_t kRemoteOutboundStatsTimestampMs = 123;
147constexpr int64_t kRemoteOutboundStatsRemoteTimestampMs = 456;
148constexpr uint32_t kRemoteOutboundStatsPacketsSent = 7u;
149constexpr uint64_t kRemoteOutboundStatsBytesSent = 8u;
150constexpr uint64_t kRemoteOutboundStatsReportsCount = 9u;
151
hbos6ab97ce02016-10-03 21:16:56152struct CertificateInfo {
153 rtc::scoped_refptr<rtc::RTCCertificate> certificate;
154 std::vector<std::string> ders;
155 std::vector<std::string> pems;
156 std::vector<std::string> fingerprints;
157};
158
Harald Alvestranda3dab842018-01-14 08:18:58159// Return the ID for an object of the given type in a report.
160// The object must be present and be unique.
161template <typename T>
162std::string IdForType(const RTCStatsReport* report) {
163 auto stats_of_my_type = report->RTCStatsReport::GetStatsOfType<T>();
164 // We cannot use ASSERT here, since we're within a function.
Mirko Bonadeie12c1fe2018-07-03 10:53:23165 EXPECT_EQ(1U, stats_of_my_type.size())
Harald Alvestranda3dab842018-01-14 08:18:58166 << "Unexpected number of stats of this type";
167 if (stats_of_my_type.size() == 1) {
168 return stats_of_my_type[0]->id();
169 } else {
170 // Return something that is not going to be a valid stas ID.
171 return "Type not found";
172 }
173}
174
hbos6ab97ce02016-10-03 21:16:56175std::unique_ptr<CertificateInfo> CreateFakeCertificateAndInfoFromDers(
176 const std::vector<std::string>& ders) {
177 RTC_CHECK(!ders.empty());
178 std::unique_ptr<CertificateInfo> info(new CertificateInfo());
179 info->ders = ders;
180 for (const std::string& der : ders) {
181 info->pems.push_back(rtc::SSLIdentity::DerToPem(
Yves Gerey665174f2018-06-19 13:03:05182 "CERTIFICATE", reinterpret_cast<const unsigned char*>(der.c_str()),
hbos6ab97ce02016-10-03 21:16:56183 der.length()));
184 }
185 info->certificate =
186 rtc::RTCCertificate::Create(std::unique_ptr<rtc::FakeSSLIdentity>(
Taylor Brandstetterc3928662018-02-23 21:04:51187 new rtc::FakeSSLIdentity(info->pems)));
hbos6ab97ce02016-10-03 21:16:56188 // Strip header/footer and newline characters of PEM strings.
189 for (size_t i = 0; i < info->pems.size(); ++i) {
Steve Anton1c9c9fc2019-02-14 23:13:09190 absl::StrReplaceAll({{"-----BEGIN CERTIFICATE-----", ""},
191 {"-----END CERTIFICATE-----", ""},
192 {"\n", ""}},
193 &info->pems[i]);
hbos6ab97ce02016-10-03 21:16:56194 }
Taylor Brandstetterc3928662018-02-23 21:04:51195 // Fingerprints for the whole certificate chain, starting with leaf
196 // certificate.
Benjamin Wright6c6c9df2018-10-25 08:16:26197 const rtc::SSLCertChain& chain = info->certificate->GetSSLCertificateChain();
Taylor Brandstetterc3928662018-02-23 21:04:51198 std::unique_ptr<rtc::SSLFingerprint> fp;
199 for (size_t i = 0; i < chain.GetSize(); i++) {
Steve Anton4905edb2018-10-16 02:27:44200 fp = rtc::SSLFingerprint::Create("sha-1", chain.Get(i));
Taylor Brandstetterc3928662018-02-23 21:04:51201 EXPECT_TRUE(fp);
202 info->fingerprints.push_back(fp->GetRfc4572Fingerprint());
hbos6ab97ce02016-10-03 21:16:56203 }
204 EXPECT_EQ(info->ders.size(), info->fingerprints.size());
205 return info;
206}
207
hbosab9f6e42016-10-07 09:18:47208std::unique_ptr<cricket::Candidate> CreateFakeCandidate(
209 const std::string& hostname,
210 int port,
211 const std::string& protocol,
Gary Liu37e489c2017-11-21 18:49:36212 const rtc::AdapterType adapter_type,
hbosab9f6e42016-10-07 09:18:47213 const std::string& candidate_type,
Jonas Oreland0d13bbd2022-03-02 10:17:36214 uint32_t priority,
215 const rtc::AdapterType underlying_type_for_vpn =
216 rtc::ADAPTER_TYPE_UNKNOWN) {
hbosab9f6e42016-10-07 09:18:47217 std::unique_ptr<cricket::Candidate> candidate(new cricket::Candidate());
218 candidate->set_address(rtc::SocketAddress(hostname, port));
219 candidate->set_protocol(protocol);
Gary Liu37e489c2017-11-21 18:49:36220 candidate->set_network_type(adapter_type);
Jonas Oreland0d13bbd2022-03-02 10:17:36221 candidate->set_underlying_type_for_vpn(underlying_type_for_vpn);
hbosab9f6e42016-10-07 09:18:47222 candidate->set_type(candidate_type);
223 candidate->set_priority(priority);
Philipp Hancke0e3cd632022-09-27 08:23:09224 // Defaults for testing.
225 candidate->set_foundation("foundationIsAString");
226 candidate->set_username("iceusernamefragment");
hbosab9f6e42016-10-07 09:18:47227 return candidate;
228}
229
Taylor Brandstetter64851c02021-06-24 20:32:50230class FakeAudioProcessor : public AudioProcessorInterface {
231 public:
232 FakeAudioProcessor() {}
233 ~FakeAudioProcessor() {}
234
235 private:
236 AudioProcessorInterface::AudioProcessorStatistics GetStats(
237 bool has_recv_streams) override {
238 AudioProcessorStatistics stats;
239 stats.apm_statistics.echo_return_loss = 2.0;
240 stats.apm_statistics.echo_return_loss_enhancement = 3.0;
241 return stats;
242 }
243};
244
Yves Gerey665174f2018-06-19 13:03:05245class FakeAudioTrackForStats : public MediaStreamTrack<AudioTrackInterface> {
hbos09bc1282016-11-08 14:29:22246 public:
247 static rtc::scoped_refptr<FakeAudioTrackForStats> Create(
248 const std::string& id,
Taylor Brandstetter64851c02021-06-24 20:32:50249 MediaStreamTrackInterface::TrackState state,
250 bool create_fake_audio_processor) {
Niels Möller027c7932022-01-25 12:56:07251 auto audio_track_stats = rtc::make_ref_counted<FakeAudioTrackForStats>(id);
hbos09bc1282016-11-08 14:29:22252 audio_track_stats->set_state(state);
Taylor Brandstetter64851c02021-06-24 20:32:50253 if (create_fake_audio_processor) {
254 audio_track_stats->processor_ =
255 rtc::make_ref_counted<FakeAudioProcessor>();
256 }
hbos09bc1282016-11-08 14:29:22257 return audio_track_stats;
258 }
259
Steve Anton36b29d12017-10-30 16:57:42260 explicit FakeAudioTrackForStats(const std::string& id)
261 : MediaStreamTrack<AudioTrackInterface>(id) {}
hbos09bc1282016-11-08 14:29:22262
263 std::string kind() const override {
264 return MediaStreamTrackInterface::kAudioKind;
265 }
Harald Alvestranda6544372023-11-13 09:33:56266 AudioSourceInterface* GetSource() const override { return nullptr; }
267 void AddSink(AudioTrackSinkInterface* sink) override {}
268 void RemoveSink(AudioTrackSinkInterface* sink) override {}
hbos9e302742017-01-20 10:47:10269 bool GetSignalLevel(int* level) override { return false; }
hbos09bc1282016-11-08 14:29:22270 rtc::scoped_refptr<AudioProcessorInterface> GetAudioProcessor() override {
Taylor Brandstetter64851c02021-06-24 20:32:50271 return processor_;
hbos09bc1282016-11-08 14:29:22272 }
Taylor Brandstetter64851c02021-06-24 20:32:50273
274 private:
275 rtc::scoped_refptr<FakeAudioProcessor> processor_;
hbos09bc1282016-11-08 14:29:22276};
277
Henrik Boström646fda02019-05-22 13:49:42278class FakeVideoTrackSourceForStats : public VideoTrackSourceInterface {
279 public:
280 static rtc::scoped_refptr<FakeVideoTrackSourceForStats> Create(
281 int input_width,
282 int input_height) {
Niels Möller027c7932022-01-25 12:56:07283 return rtc::make_ref_counted<FakeVideoTrackSourceForStats>(input_width,
284 input_height);
Henrik Boström646fda02019-05-22 13:49:42285 }
286
287 FakeVideoTrackSourceForStats(int input_width, int input_height)
288 : input_width_(input_width), input_height_(input_height) {}
289 ~FakeVideoTrackSourceForStats() override {}
290
291 // VideoTrackSourceInterface
292 bool is_screencast() const override { return false; }
293 absl::optional<bool> needs_denoising() const override { return false; }
294 bool GetStats(VideoTrackSourceInterface::Stats* stats) override {
295 stats->input_width = input_width_;
296 stats->input_height = input_height_;
297 return true;
298 }
299 // MediaSourceInterface (part of VideoTrackSourceInterface)
300 MediaSourceInterface::SourceState state() const override {
301 return MediaSourceInterface::SourceState::kLive;
302 }
303 bool remote() const override { return false; }
304 // NotifierInterface (part of MediaSourceInterface)
305 void RegisterObserver(ObserverInterface* observer) override {}
306 void UnregisterObserver(ObserverInterface* observer) override {}
307 // rtc::VideoSourceInterface<VideoFrame> (part of VideoTrackSourceInterface)
308 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
309 const rtc::VideoSinkWants& wants) override {}
310 void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override {}
Markus Handell6efc14b2020-05-05 18:11:13311 bool SupportsEncodedOutput() const override { return false; }
312 void GenerateKeyFrame() override {}
313 void AddEncodedSink(
314 rtc::VideoSinkInterface<RecordableEncodedFrame>* sink) override {}
315 void RemoveEncodedSink(
316 rtc::VideoSinkInterface<RecordableEncodedFrame>* sink) override {}
Henrik Boström646fda02019-05-22 13:49:42317
318 private:
319 int input_width_;
320 int input_height_;
321};
322
Yves Gerey665174f2018-06-19 13:03:05323class FakeVideoTrackForStats : public MediaStreamTrack<VideoTrackInterface> {
hbos09bc1282016-11-08 14:29:22324 public:
325 static rtc::scoped_refptr<FakeVideoTrackForStats> Create(
326 const std::string& id,
Henrik Boström646fda02019-05-22 13:49:42327 MediaStreamTrackInterface::TrackState state,
328 rtc::scoped_refptr<VideoTrackSourceInterface> source) {
Niels Möller027c7932022-01-25 12:56:07329 auto video_track =
330 rtc::make_ref_counted<FakeVideoTrackForStats>(id, std::move(source));
hbos09bc1282016-11-08 14:29:22331 video_track->set_state(state);
332 return video_track;
333 }
334
Henrik Boström646fda02019-05-22 13:49:42335 FakeVideoTrackForStats(const std::string& id,
336 rtc::scoped_refptr<VideoTrackSourceInterface> source)
337 : MediaStreamTrack<VideoTrackInterface>(id), source_(source) {}
hbos09bc1282016-11-08 14:29:22338
339 std::string kind() const override {
340 return MediaStreamTrackInterface::kVideoKind;
341 }
perkj773be362017-08-01 06:22:01342
343 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
Mirko Bonadeic4dd7302019-02-25 08:12:02344 const rtc::VideoSinkWants& wants) override {}
345 void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override {}
perkj773be362017-08-01 06:22:01346
Henrik Boström646fda02019-05-22 13:49:42347 VideoTrackSourceInterface* GetSource() const override {
348 return source_.get();
349 }
350
351 private:
352 rtc::scoped_refptr<VideoTrackSourceInterface> source_;
hbos09bc1282016-11-08 14:29:22353};
354
hbos84abeb12017-01-16 14:16:44355rtc::scoped_refptr<MediaStreamTrackInterface> CreateFakeTrack(
356 cricket::MediaType media_type,
hbos9e302742017-01-20 10:47:10357 const std::string& track_id,
Taylor Brandstetter64851c02021-06-24 20:32:50358 MediaStreamTrackInterface::TrackState track_state,
359 bool create_fake_audio_processor = false) {
hbos84abeb12017-01-16 14:16:44360 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
Taylor Brandstetter64851c02021-06-24 20:32:50361 return FakeAudioTrackForStats::Create(track_id, track_state,
362 create_fake_audio_processor);
hbos84abeb12017-01-16 14:16:44363 } else {
364 RTC_DCHECK_EQ(media_type, cricket::MEDIA_TYPE_VIDEO);
Henrik Boström646fda02019-05-22 13:49:42365 return FakeVideoTrackForStats::Create(track_id, track_state, nullptr);
hbos84abeb12017-01-16 14:16:44366 }
367}
368
Steve Anton57858b32018-02-15 23:19:50369rtc::scoped_refptr<MockRtpSenderInternal> CreateMockSender(
Henrik Boström646fda02019-05-22 13:49:42370 cricket::MediaType media_type,
371 rtc::scoped_refptr<MediaStreamTrackInterface> track,
Harald Alvestrandc72af932018-01-11 16:18:19372 uint32_t ssrc,
Harald Alvestranda3dab842018-01-14 08:18:58373 int attachment_id,
374 std::vector<std::string> local_stream_ids) {
Henrik Boström646fda02019-05-22 13:49:42375 RTC_DCHECK(!track ||
376 (track->kind() == MediaStreamTrackInterface::kAudioKind &&
377 media_type == cricket::MEDIA_TYPE_AUDIO) ||
378 (track->kind() == MediaStreamTrackInterface::kVideoKind &&
379 media_type == cricket::MEDIA_TYPE_VIDEO));
Niels Möller027c7932022-01-25 12:56:07380 auto sender = rtc::make_ref_counted<MockRtpSenderInternal>();
hbos9e302742017-01-20 10:47:10381 EXPECT_CALL(*sender, track()).WillRepeatedly(Return(track));
382 EXPECT_CALL(*sender, ssrc()).WillRepeatedly(Return(ssrc));
Henrik Boström646fda02019-05-22 13:49:42383 EXPECT_CALL(*sender, media_type()).WillRepeatedly(Return(media_type));
Henrik Boström175f06f2023-01-05 07:53:16384 EXPECT_CALL(*sender, GetParameters())
385 .WillRepeatedly(
386 Invoke([s = sender.get()]() { return s->GetParametersInternal(); }));
387 EXPECT_CALL(*sender, GetParametersInternal()).WillRepeatedly(Invoke([ssrc]() {
Yves Gerey665174f2018-06-19 13:03:05388 RtpParameters params;
389 params.encodings.push_back(RtpEncodingParameters());
390 params.encodings[0].ssrc = ssrc;
391 return params;
392 }));
Harald Alvestrandc72af932018-01-11 16:18:19393 EXPECT_CALL(*sender, AttachmentId()).WillRepeatedly(Return(attachment_id));
Harald Alvestranda3dab842018-01-14 08:18:58394 EXPECT_CALL(*sender, stream_ids()).WillRepeatedly(Return(local_stream_ids));
Alessio Bazzica049e6112021-03-18 11:55:11395 EXPECT_CALL(*sender, SetTransceiverAsStopped());
hbos9e302742017-01-20 10:47:10396 return sender;
397}
398
Steve Anton57858b32018-02-15 23:19:50399rtc::scoped_refptr<MockRtpReceiverInternal> CreateMockReceiver(
Mirko Bonadeic61ce0d2017-11-21 16:04:20400 const rtc::scoped_refptr<MediaStreamTrackInterface>& track,
Harald Alvestrandc72af932018-01-11 16:18:19401 uint32_t ssrc,
402 int attachment_id) {
Niels Möller027c7932022-01-25 12:56:07403 auto receiver = rtc::make_ref_counted<MockRtpReceiverInternal>();
hbos9e302742017-01-20 10:47:10404 EXPECT_CALL(*receiver, track()).WillRepeatedly(Return(track));
Henrik Boström175f06f2023-01-05 07:53:16405 EXPECT_CALL(*receiver, ssrc()).WillRepeatedly(Invoke([ssrc]() {
406 return ssrc;
407 }));
Harald Alvestranda3dab842018-01-14 08:18:58408 EXPECT_CALL(*receiver, streams())
409 .WillRepeatedly(
410 Return(std::vector<rtc::scoped_refptr<MediaStreamInterface>>({})));
411
Yves Gerey665174f2018-06-19 13:03:05412 EXPECT_CALL(*receiver, media_type())
413 .WillRepeatedly(
414 Return(track->kind() == MediaStreamTrackInterface::kAudioKind
415 ? cricket::MEDIA_TYPE_AUDIO
416 : cricket::MEDIA_TYPE_VIDEO));
417 EXPECT_CALL(*receiver, GetParameters()).WillRepeatedly(Invoke([ssrc]() {
418 RtpParameters params;
419 params.encodings.push_back(RtpEncodingParameters());
420 params.encodings[0].ssrc = ssrc;
421 return params;
422 }));
Harald Alvestrandc72af932018-01-11 16:18:19423 EXPECT_CALL(*receiver, AttachmentId()).WillRepeatedly(Return(attachment_id));
Tommi6589def2022-02-17 22:36:47424 EXPECT_CALL(*receiver, Stop()).WillRepeatedly(Return());
hbos9e302742017-01-20 10:47:10425 return receiver;
426}
427
Steve Anton5b387312018-02-03 00:00:20428class RTCStatsCollectorWrapper {
hbosd565b732016-08-30 21:04:35429 public:
Steve Anton5b387312018-02-03 00:00:20430 explicit RTCStatsCollectorWrapper(
431 rtc::scoped_refptr<FakePeerConnectionForStats> pc)
432 : pc_(pc),
433 stats_collector_(
Niels Möllerafb246b2022-04-20 12:26:50434 RTCStatsCollector::Create(pc.get(),
435 50 * rtc::kNumMicrosecsPerMillisec)) {}
hbosd565b732016-08-30 21:04:35436
Steve Anton5b387312018-02-03 00:00:20437 rtc::scoped_refptr<RTCStatsCollector> stats_collector() {
438 return stats_collector_;
hbosd565b732016-08-30 21:04:35439 }
440
Henrik Boström5b3541f2018-03-19 12:52:56441 rtc::scoped_refptr<const RTCStatsReport> GetStatsReport() {
442 rtc::scoped_refptr<RTCStatsObtainer> callback = RTCStatsObtainer::Create();
443 stats_collector_->GetStatsReport(callback);
444 return WaitForReport(callback);
445 }
446
447 rtc::scoped_refptr<const RTCStatsReport> GetStatsReportWithSenderSelector(
448 rtc::scoped_refptr<RtpSenderInternal> selector) {
449 rtc::scoped_refptr<RTCStatsObtainer> callback = RTCStatsObtainer::Create();
450 stats_collector_->GetStatsReport(selector, callback);
451 return WaitForReport(callback);
452 }
453
454 rtc::scoped_refptr<const RTCStatsReport> GetStatsReportWithReceiverSelector(
455 rtc::scoped_refptr<RtpReceiverInternal> selector) {
456 rtc::scoped_refptr<RTCStatsObtainer> callback = RTCStatsObtainer::Create();
457 stats_collector_->GetStatsReport(selector, callback);
458 return WaitForReport(callback);
459 }
460
Steve Anton5b387312018-02-03 00:00:20461 rtc::scoped_refptr<const RTCStatsReport> GetFreshStatsReport() {
462 stats_collector_->ClearCachedStatsReport();
463 return GetStatsReport();
464 }
465
Henrik Boström5b3541f2018-03-19 12:52:56466 rtc::scoped_refptr<MockRtpSenderInternal> SetupLocalTrackAndSender(
467 cricket::MediaType media_type,
468 const std::string& track_id,
469 uint32_t ssrc,
Henrik Boström646fda02019-05-22 13:49:42470 bool add_stream,
471 int attachment_id) {
Harald Alvestrand89061872018-01-02 13:08:34472 rtc::scoped_refptr<MediaStream> local_stream;
473 if (add_stream) {
Seth Hampson845e8782018-03-02 19:34:10474 local_stream = MediaStream::Create("LocalStreamId");
Steve Anton5b387312018-02-03 00:00:20475 pc_->mutable_local_streams()->AddStream(local_stream);
Harald Alvestrand89061872018-01-02 13:08:34476 }
hbos84abeb12017-01-16 14:16:44477
478 rtc::scoped_refptr<MediaStreamTrackInterface> track;
479 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
hbos9e302742017-01-20 10:47:10480 track = CreateFakeTrack(media_type, track_id,
481 MediaStreamTrackInterface::kLive);
Harald Alvestrand89061872018-01-02 13:08:34482 if (add_stream) {
Harald Alvestrand2f7ad282022-04-21 11:35:43483 local_stream->AddTrack(rtc::scoped_refptr<AudioTrackInterface>(
484 static_cast<AudioTrackInterface*>(track.get())));
Harald Alvestrand89061872018-01-02 13:08:34485 }
hbos84abeb12017-01-16 14:16:44486 } else {
hbos9e302742017-01-20 10:47:10487 track = CreateFakeTrack(media_type, track_id,
488 MediaStreamTrackInterface::kLive);
Harald Alvestrand89061872018-01-02 13:08:34489 if (add_stream) {
Harald Alvestrand2f7ad282022-04-21 11:35:43490 local_stream->AddTrack(rtc::scoped_refptr<VideoTrackInterface>(
491 static_cast<VideoTrackInterface*>(track.get())));
Harald Alvestrand89061872018-01-02 13:08:34492 }
hbos84abeb12017-01-16 14:16:44493 }
494
Steve Anton57858b32018-02-15 23:19:50495 rtc::scoped_refptr<MockRtpSenderInternal> sender =
Henrik Boström646fda02019-05-22 13:49:42496 CreateMockSender(media_type, track, ssrc, attachment_id, {});
Tommi6589def2022-02-17 22:36:47497 EXPECT_CALL(*sender, Stop());
498 EXPECT_CALL(*sender, SetMediaChannel(_));
Steve Anton5b387312018-02-03 00:00:20499 pc_->AddSender(sender);
Henrik Boström5b3541f2018-03-19 12:52:56500 return sender;
hbos84abeb12017-01-16 14:16:44501 }
502
Henrik Boström5b3541f2018-03-19 12:52:56503 rtc::scoped_refptr<MockRtpReceiverInternal> SetupRemoteTrackAndReceiver(
504 cricket::MediaType media_type,
505 const std::string& track_id,
506 const std::string& stream_id,
507 uint32_t ssrc) {
hbos84abeb12017-01-16 14:16:44508 rtc::scoped_refptr<MediaStream> remote_stream =
Henrik Boström5b3541f2018-03-19 12:52:56509 MediaStream::Create(stream_id);
Steve Anton5b387312018-02-03 00:00:20510 pc_->mutable_remote_streams()->AddStream(remote_stream);
hbos84abeb12017-01-16 14:16:44511
512 rtc::scoped_refptr<MediaStreamTrackInterface> track;
513 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
hbos9e302742017-01-20 10:47:10514 track = CreateFakeTrack(media_type, track_id,
515 MediaStreamTrackInterface::kLive);
Harald Alvestrand2f7ad282022-04-21 11:35:43516 remote_stream->AddTrack(rtc::scoped_refptr<AudioTrackInterface>(
517 static_cast<AudioTrackInterface*>(track.get())));
hbos84abeb12017-01-16 14:16:44518 } else {
hbos9e302742017-01-20 10:47:10519 track = CreateFakeTrack(media_type, track_id,
520 MediaStreamTrackInterface::kLive);
Harald Alvestrand2f7ad282022-04-21 11:35:43521 remote_stream->AddTrack(rtc::scoped_refptr<VideoTrackInterface>(
522 static_cast<VideoTrackInterface*>(track.get())));
hbos84abeb12017-01-16 14:16:44523 }
524
Steve Anton57858b32018-02-15 23:19:50525 rtc::scoped_refptr<MockRtpReceiverInternal> receiver =
Harald Alvestrandc72af932018-01-11 16:18:19526 CreateMockReceiver(track, ssrc, 62);
Harald Alvestranda3dab842018-01-14 08:18:58527 EXPECT_CALL(*receiver, streams())
528 .WillRepeatedly(
529 Return(std::vector<rtc::scoped_refptr<MediaStreamInterface>>(
530 {remote_stream})));
Tommi6589def2022-02-17 22:36:47531 EXPECT_CALL(*receiver, SetMediaChannel(_)).WillRepeatedly(Return());
Steve Anton5b387312018-02-03 00:00:20532 pc_->AddReceiver(receiver);
Henrik Boström5b3541f2018-03-19 12:52:56533 return receiver;
hbos84abeb12017-01-16 14:16:44534 }
535
hbos9e302742017-01-20 10:47:10536 // Attaches tracks to peer connections by configuring RTP senders and RTP
537 // receivers according to the tracks' pairings with
538 // |[Voice/Video][Sender/Receiver]Info| and their SSRCs. Local tracks can be
539 // associated with multiple |[Voice/Video]SenderInfo|s, remote tracks can only
540 // be associated with one |[Voice/Video]ReceiverInfo|.
Henrik Boström646fda02019-05-22 13:49:42541 // Senders get assigned attachment ID "ssrc + 10".
hbos9e302742017-01-20 10:47:10542 void CreateMockRtpSendersReceiversAndChannels(
Harald Alvestranda3dab842018-01-14 08:18:58543 std::initializer_list<
544 std::pair<MediaStreamTrackInterface*, cricket::VoiceSenderInfo>>
545 local_audio_track_info_pairs,
546 std::initializer_list<
547 std::pair<MediaStreamTrackInterface*, cricket::VoiceReceiverInfo>>
548 remote_audio_track_info_pairs,
549 std::initializer_list<
550 std::pair<MediaStreamTrackInterface*, cricket::VideoSenderInfo>>
551 local_video_track_info_pairs,
552 std::initializer_list<
553 std::pair<MediaStreamTrackInterface*, cricket::VideoReceiverInfo>>
554 remote_video_track_info_pairs,
555 std::vector<std::string> local_stream_ids,
556 std::vector<rtc::scoped_refptr<MediaStreamInterface>> remote_streams) {
Steve Anton5b387312018-02-03 00:00:20557 cricket::VoiceMediaInfo voice_media_info;
558 cricket::VideoMediaInfo video_media_info;
559
hbos9e302742017-01-20 10:47:10560 // Local audio tracks and voice sender infos
561 for (auto& pair : local_audio_track_info_pairs) {
562 MediaStreamTrackInterface* local_audio_track = pair.first;
563 const cricket::VoiceSenderInfo& voice_sender_info = pair.second;
564 RTC_DCHECK_EQ(local_audio_track->kind(),
565 MediaStreamTrackInterface::kAudioKind);
566
Steve Anton5b387312018-02-03 00:00:20567 voice_media_info.senders.push_back(voice_sender_info);
Steve Anton57858b32018-02-15 23:19:50568 rtc::scoped_refptr<MockRtpSenderInternal> rtp_sender = CreateMockSender(
Henrik Boström646fda02019-05-22 13:49:42569 cricket::MEDIA_TYPE_AUDIO,
Harald Alvestrandc72af932018-01-11 16:18:19570 rtc::scoped_refptr<MediaStreamTrackInterface>(local_audio_track),
Henrik Boström646fda02019-05-22 13:49:42571 voice_sender_info.local_stats[0].ssrc,
572 voice_sender_info.local_stats[0].ssrc + 10, local_stream_ids);
Tomas Gunnarsson16de2162022-01-26 09:21:57573 EXPECT_CALL(*rtp_sender, SetMediaChannel(_)).WillRepeatedly(Return());
Tommi6589def2022-02-17 22:36:47574 EXPECT_CALL(*rtp_sender, Stop());
Steve Anton5b387312018-02-03 00:00:20575 pc_->AddSender(rtp_sender);
hbos9e302742017-01-20 10:47:10576 }
Steve Anton5b387312018-02-03 00:00:20577
hbos9e302742017-01-20 10:47:10578 // Remote audio tracks and voice receiver infos
579 for (auto& pair : remote_audio_track_info_pairs) {
580 MediaStreamTrackInterface* remote_audio_track = pair.first;
581 const cricket::VoiceReceiverInfo& voice_receiver_info = pair.second;
582 RTC_DCHECK_EQ(remote_audio_track->kind(),
583 MediaStreamTrackInterface::kAudioKind);
584
Steve Anton5b387312018-02-03 00:00:20585 voice_media_info.receivers.push_back(voice_receiver_info);
Steve Anton57858b32018-02-15 23:19:50586 rtc::scoped_refptr<MockRtpReceiverInternal> rtp_receiver =
587 CreateMockReceiver(
588 rtc::scoped_refptr<MediaStreamTrackInterface>(remote_audio_track),
Henrik Boström646fda02019-05-22 13:49:42589 voice_receiver_info.local_stats[0].ssrc,
590 voice_receiver_info.local_stats[0].ssrc + 10);
Harald Alvestranda3dab842018-01-14 08:18:58591 EXPECT_CALL(*rtp_receiver, streams())
592 .WillRepeatedly(Return(remote_streams));
Tommi6589def2022-02-17 22:36:47593 EXPECT_CALL(*rtp_receiver, SetMediaChannel(_)).WillRepeatedly(Return());
Steve Anton5b387312018-02-03 00:00:20594 pc_->AddReceiver(rtp_receiver);
hbos9e302742017-01-20 10:47:10595 }
Steve Anton5b387312018-02-03 00:00:20596
hbos9e302742017-01-20 10:47:10597 // Local video tracks and video sender infos
598 for (auto& pair : local_video_track_info_pairs) {
599 MediaStreamTrackInterface* local_video_track = pair.first;
600 const cricket::VideoSenderInfo& video_sender_info = pair.second;
601 RTC_DCHECK_EQ(local_video_track->kind(),
602 MediaStreamTrackInterface::kVideoKind);
603
Steve Anton5b387312018-02-03 00:00:20604 video_media_info.senders.push_back(video_sender_info);
Henrik Boströma0ff50c2020-05-05 13:54:46605 video_media_info.aggregated_senders.push_back(video_sender_info);
Steve Anton57858b32018-02-15 23:19:50606 rtc::scoped_refptr<MockRtpSenderInternal> rtp_sender = CreateMockSender(
Henrik Boström646fda02019-05-22 13:49:42607 cricket::MEDIA_TYPE_VIDEO,
Harald Alvestrandc72af932018-01-11 16:18:19608 rtc::scoped_refptr<MediaStreamTrackInterface>(local_video_track),
Henrik Boström646fda02019-05-22 13:49:42609 video_sender_info.local_stats[0].ssrc,
610 video_sender_info.local_stats[0].ssrc + 10, local_stream_ids);
Tomas Gunnarsson16de2162022-01-26 09:21:57611 EXPECT_CALL(*rtp_sender, SetMediaChannel(_)).WillRepeatedly(Return());
Tommi6589def2022-02-17 22:36:47612 EXPECT_CALL(*rtp_sender, Stop());
Steve Anton5b387312018-02-03 00:00:20613 pc_->AddSender(rtp_sender);
hbos9e302742017-01-20 10:47:10614 }
Steve Anton5b387312018-02-03 00:00:20615
hbos9e302742017-01-20 10:47:10616 // Remote video tracks and video receiver infos
617 for (auto& pair : remote_video_track_info_pairs) {
618 MediaStreamTrackInterface* remote_video_track = pair.first;
619 const cricket::VideoReceiverInfo& video_receiver_info = pair.second;
620 RTC_DCHECK_EQ(remote_video_track->kind(),
621 MediaStreamTrackInterface::kVideoKind);
622
Steve Anton5b387312018-02-03 00:00:20623 video_media_info.receivers.push_back(video_receiver_info);
Steve Anton57858b32018-02-15 23:19:50624 rtc::scoped_refptr<MockRtpReceiverInternal> rtp_receiver =
625 CreateMockReceiver(
626 rtc::scoped_refptr<MediaStreamTrackInterface>(remote_video_track),
Henrik Boström646fda02019-05-22 13:49:42627 video_receiver_info.local_stats[0].ssrc,
628 video_receiver_info.local_stats[0].ssrc + 10);
Harald Alvestranda3dab842018-01-14 08:18:58629 EXPECT_CALL(*rtp_receiver, streams())
630 .WillRepeatedly(Return(remote_streams));
Tommi6589def2022-02-17 22:36:47631 EXPECT_CALL(*rtp_receiver, SetMediaChannel(_)).WillRepeatedly(Return());
Steve Anton5b387312018-02-03 00:00:20632 pc_->AddReceiver(rtp_receiver);
hbos9e302742017-01-20 10:47:10633 }
hbos9e302742017-01-20 10:47:10634
Tommi19015512022-02-02 10:49:35635 pc_->AddVoiceChannel("audio", "transport", voice_media_info);
636 pc_->AddVideoChannel("video", "transport", video_media_info);
hbos9e302742017-01-20 10:47:10637 }
638
hbosd565b732016-08-30 21:04:35639 private:
Henrik Boström5b3541f2018-03-19 12:52:56640 rtc::scoped_refptr<const RTCStatsReport> WaitForReport(
641 rtc::scoped_refptr<RTCStatsObtainer> callback) {
Niels Möllerafb246b2022-04-20 12:26:50642 EXPECT_TRUE_WAIT(callback->report() != nullptr, kGetStatsReportTimeoutMs);
Henrik Boström5b3541f2018-03-19 12:52:56643 int64_t after = rtc::TimeUTCMicros();
644 for (const RTCStats& stats : *callback->report()) {
Alessio Bazzicaf7b1b952021-03-23 16:23:04645 if (stats.type() == RTCRemoteInboundRtpStreamStats::kType ||
646 stats.type() == RTCRemoteOutboundRtpStreamStats::kType) {
647 // Ignore remote timestamps.
648 continue;
649 }
Philipp Hanckeb81823a2023-01-04 14:17:42650 EXPECT_LE(stats.timestamp().us(), after);
Henrik Boström5b3541f2018-03-19 12:52:56651 }
652 return callback->report();
653 }
654
Steve Anton5b387312018-02-03 00:00:20655 rtc::scoped_refptr<FakePeerConnectionForStats> pc_;
656 rtc::scoped_refptr<RTCStatsCollector> stats_collector_;
hbosd565b732016-08-30 21:04:35657};
658
Mirko Bonadei6a489f22019-04-09 13:11:12659class RTCStatsCollectorTest : public ::testing::Test {
hbosc82f2e12016-09-05 08:36:50660 public:
661 RTCStatsCollectorTest()
Niels Möller027c7932022-01-25 12:56:07662 : pc_(rtc::make_ref_counted<FakePeerConnectionForStats>()),
Tommifaf33872023-03-16 08:25:29663 stats_(new RTCStatsCollectorWrapper(pc_)),
Tommi55f72802023-03-27 10:39:33664 data_channel_controller_(
665 new FakeDataChannelController(pc_->network_thread())) {}
hbosc82f2e12016-09-05 08:36:50666
hbos6ab97ce02016-10-03 21:16:56667 void ExpectReportContainsCertificateInfo(
668 const rtc::scoped_refptr<const RTCStatsReport>& report,
hbos23368e12016-12-21 12:29:17669 const CertificateInfo& certinfo) {
670 for (size_t i = 0; i < certinfo.fingerprints.size(); ++i) {
671 RTCCertificateStats expected_certificate_stats(
Philipp Hanckeb81823a2023-01-04 14:17:42672 "CF" + certinfo.fingerprints[i], report->timestamp());
hbos23368e12016-12-21 12:29:17673 expected_certificate_stats.fingerprint = certinfo.fingerprints[i];
674 expected_certificate_stats.fingerprint_algorithm = "sha-1";
675 expected_certificate_stats.base64_certificate = certinfo.pems[i];
676 if (i + 1 < certinfo.fingerprints.size()) {
677 expected_certificate_stats.issuer_certificate_id =
Henrik Boström8dfc90f2022-09-02 07:39:29678 "CF" + certinfo.fingerprints[i + 1];
hbos6ab97ce02016-10-03 21:16:56679 }
hbos23368e12016-12-21 12:29:17680 ASSERT_TRUE(report->Get(expected_certificate_stats.id()));
681 EXPECT_EQ(expected_certificate_stats,
Yves Gerey665174f2018-06-19 13:03:05682 report->Get(expected_certificate_stats.id())
683 ->cast_to<RTCCertificateStats>());
hbos6ab97ce02016-10-03 21:16:56684 }
685 }
686
Henrik Boström69d23c92022-09-26 12:13:17687 const RTCCertificateStats* GetCertificateStatsFromFingerprint(
688 const rtc::scoped_refptr<const RTCStatsReport>& report,
689 const std::string& fingerprint) {
690 auto certificates = report->GetStatsOfType<RTCCertificateStats>();
691 for (const auto* certificate : certificates) {
692 if (*certificate->fingerprint == fingerprint) {
693 return certificate;
694 }
695 }
696 return nullptr;
697 }
698
Henrik Boström5b3541f2018-03-19 12:52:56699 struct ExampleStatsGraph {
700 rtc::scoped_refptr<RtpSenderInternal> sender;
701 rtc::scoped_refptr<RtpReceiverInternal> receiver;
702
703 rtc::scoped_refptr<const RTCStatsReport> full_report;
704 std::string send_codec_id;
705 std::string recv_codec_id;
706 std::string outbound_rtp_id;
707 std::string inbound_rtp_id;
Alessio Bazzicaf7b1b952021-03-23 16:23:04708 std::string remote_outbound_rtp_id;
Henrik Boström5b3541f2018-03-19 12:52:56709 std::string transport_id;
Henrik Boström5b3541f2018-03-19 12:52:56710 std::string peer_connection_id;
Henrik Boström646fda02019-05-22 13:49:42711 std::string media_source_id;
Henrik Boström5b3541f2018-03-19 12:52:56712 };
713
Alessio Bazzicaf7b1b952021-03-23 16:23:04714 // Sets up the example stats graph (see ASCII art below) for a video only
715 // call. The graph is used for testing the stats selection algorithm (see
716 // https://w3c.github.io/webrtc-pc/#dfn-stats-selection-algorithm).
Henrik Boström5b3541f2018-03-19 12:52:56717 // These tests test the integration of the stats traversal algorithm inside of
718 // RTCStatsCollector. See rtcstatstraveral_unittest.cc for more stats
719 // traversal tests.
720 ExampleStatsGraph SetupExampleStatsGraphForSelectorTests() {
721 ExampleStatsGraph graph;
722
723 // codec (send)
Henrik Boström8dfc90f2022-09-02 07:39:29724 graph.send_codec_id = "COTTransportName1_1";
Henrik Boström5b3541f2018-03-19 12:52:56725 cricket::VideoMediaInfo video_media_info;
726 RtpCodecParameters send_codec;
727 send_codec.payload_type = 1;
728 send_codec.clock_rate = 0;
729 video_media_info.send_codecs.insert(
730 std::make_pair(send_codec.payload_type, send_codec));
731 // codec (recv)
Henrik Boström8dfc90f2022-09-02 07:39:29732 graph.recv_codec_id = "CITTransportName1_2";
Henrik Boström5b3541f2018-03-19 12:52:56733 RtpCodecParameters recv_codec;
734 recv_codec.payload_type = 2;
735 recv_codec.clock_rate = 0;
736 video_media_info.receive_codecs.insert(
737 std::make_pair(recv_codec.payload_type, recv_codec));
738 // outbound-rtp
Henrik Boströmb43e3bb2022-09-26 10:36:44739 graph.outbound_rtp_id = "OTTransportName1V3";
Henrik Boström5b3541f2018-03-19 12:52:56740 video_media_info.senders.push_back(cricket::VideoSenderInfo());
741 video_media_info.senders[0].local_stats.push_back(
742 cricket::SsrcSenderInfo());
743 video_media_info.senders[0].local_stats[0].ssrc = 3;
744 video_media_info.senders[0].codec_payload_type = send_codec.payload_type;
Henrik Boströma0ff50c2020-05-05 13:54:46745 video_media_info.aggregated_senders.push_back(video_media_info.senders[0]);
Henrik Boström5b3541f2018-03-19 12:52:56746 // inbound-rtp
Henrik Boströmb43e3bb2022-09-26 10:36:44747 graph.inbound_rtp_id = "ITTransportName1V4";
Henrik Boström5b3541f2018-03-19 12:52:56748 video_media_info.receivers.push_back(cricket::VideoReceiverInfo());
749 video_media_info.receivers[0].local_stats.push_back(
750 cricket::SsrcReceiverInfo());
751 video_media_info.receivers[0].local_stats[0].ssrc = 4;
752 video_media_info.receivers[0].codec_payload_type = recv_codec.payload_type;
753 // transport
Henrik Boström8dfc90f2022-09-02 07:39:29754 graph.transport_id = "TTransportName1";
Tommi19015512022-02-02 10:49:35755 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström4e231ee2023-05-24 09:24:13756 // outbound-rtp's sender
Henrik Boström5b3541f2018-03-19 12:52:56757 graph.sender = stats_->SetupLocalTrackAndSender(
Henrik Boström646fda02019-05-22 13:49:42758 cricket::MEDIA_TYPE_VIDEO, "LocalVideoTrackID", 3, false, 50);
Henrik Boström4e231ee2023-05-24 09:24:13759 // inbound-rtp's receiver
Henrik Boström5b3541f2018-03-19 12:52:56760 graph.receiver = stats_->SetupRemoteTrackAndReceiver(
761 cricket::MEDIA_TYPE_VIDEO, "RemoteVideoTrackID", "RemoteStreamId", 4);
Henrik Boström5b3541f2018-03-19 12:52:56762 // peer-connection
Henrik Boström8dfc90f2022-09-02 07:39:29763 graph.peer_connection_id = "P";
Henrik Boström646fda02019-05-22 13:49:42764 // media-source (kind: video)
Henrik Boström8dfc90f2022-09-02 07:39:29765 graph.media_source_id = "SV" + rtc::ToString(graph.sender->AttachmentId());
Henrik Boström5b3541f2018-03-19 12:52:56766
767 // Expected stats graph:
768 //
Henrik Boström4e231ee2023-05-24 09:24:13769 // media-source peer-connection
770 // ^
771 // |
772 // +--------- outbound-rtp inbound-rtp
773 // | | | |
774 // v v v v
775 // codec (send) transport codec (recv)
Henrik Boström5b3541f2018-03-19 12:52:56776
777 // Verify the stats graph is set up correctly.
778 graph.full_report = stats_->GetStatsReport();
Henrik Boström4e231ee2023-05-24 09:24:13779 EXPECT_EQ(graph.full_report->size(), 7u);
Henrik Boström5b3541f2018-03-19 12:52:56780 EXPECT_TRUE(graph.full_report->Get(graph.send_codec_id));
781 EXPECT_TRUE(graph.full_report->Get(graph.recv_codec_id));
782 EXPECT_TRUE(graph.full_report->Get(graph.outbound_rtp_id));
783 EXPECT_TRUE(graph.full_report->Get(graph.inbound_rtp_id));
784 EXPECT_TRUE(graph.full_report->Get(graph.transport_id));
Henrik Boström5b3541f2018-03-19 12:52:56785 EXPECT_TRUE(graph.full_report->Get(graph.peer_connection_id));
Henrik Boström646fda02019-05-22 13:49:42786 EXPECT_TRUE(graph.full_report->Get(graph.media_source_id));
Henrik Boström5b3541f2018-03-19 12:52:56787 const auto& outbound_rtp = graph.full_report->Get(graph.outbound_rtp_id)
Philipp Hancke1f98b462023-03-07 08:53:59788 ->cast_to<RTCOutboundRtpStreamStats>();
Henrik Boström646fda02019-05-22 13:49:42789 EXPECT_EQ(*outbound_rtp.media_source_id, graph.media_source_id);
Henrik Boström5b3541f2018-03-19 12:52:56790 EXPECT_EQ(*outbound_rtp.codec_id, graph.send_codec_id);
Henrik Boström5b3541f2018-03-19 12:52:56791 EXPECT_EQ(*outbound_rtp.transport_id, graph.transport_id);
Harald Alvestrand2f553702023-03-07 10:10:03792 EXPECT_TRUE(graph.full_report->Get(graph.inbound_rtp_id));
793 // We can't use an ASSERT in a function returning non-void, so just return.
794 if (!graph.full_report->Get(graph.inbound_rtp_id)) {
795 return graph;
796 }
Henrik Boström5b3541f2018-03-19 12:52:56797 const auto& inbound_rtp = graph.full_report->Get(graph.inbound_rtp_id)
Philipp Hancke1f98b462023-03-07 08:53:59798 ->cast_to<RTCInboundRtpStreamStats>();
Henrik Boström5b3541f2018-03-19 12:52:56799 EXPECT_EQ(*inbound_rtp.codec_id, graph.recv_codec_id);
Henrik Boström5b3541f2018-03-19 12:52:56800 EXPECT_EQ(*inbound_rtp.transport_id, graph.transport_id);
801
802 return graph;
803 }
804
Alessio Bazzicaf7b1b952021-03-23 16:23:04805 // Sets up an example stats graph (see ASCII art below) for an audio only call
806 // and checks that the expected stats are generated.
807 ExampleStatsGraph SetupExampleStatsVoiceGraph(
808 bool add_remote_outbound_stats) {
809 constexpr uint32_t kLocalSsrc = 3;
810 constexpr uint32_t kRemoteSsrc = 4;
811 ExampleStatsGraph graph;
812
813 // codec (send)
Henrik Boström8dfc90f2022-09-02 07:39:29814 graph.send_codec_id = "COTTransportName1_1";
Alessio Bazzicaf7b1b952021-03-23 16:23:04815 cricket::VoiceMediaInfo media_info;
816 RtpCodecParameters send_codec;
817 send_codec.payload_type = 1;
818 send_codec.clock_rate = 0;
819 media_info.send_codecs.insert(
820 std::make_pair(send_codec.payload_type, send_codec));
821 // codec (recv)
Henrik Boström8dfc90f2022-09-02 07:39:29822 graph.recv_codec_id = "CITTransportName1_2";
Alessio Bazzicaf7b1b952021-03-23 16:23:04823 RtpCodecParameters recv_codec;
824 recv_codec.payload_type = 2;
825 recv_codec.clock_rate = 0;
826 media_info.receive_codecs.insert(
827 std::make_pair(recv_codec.payload_type, recv_codec));
828 // outbound-rtp
Henrik Boströmb43e3bb2022-09-26 10:36:44829 graph.outbound_rtp_id = "OTTransportName1A3";
Alessio Bazzicaf7b1b952021-03-23 16:23:04830 media_info.senders.push_back(cricket::VoiceSenderInfo());
831 media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
832 media_info.senders[0].local_stats[0].ssrc = kLocalSsrc;
833 media_info.senders[0].codec_payload_type = send_codec.payload_type;
834 // inbound-rtp
Henrik Boströmb43e3bb2022-09-26 10:36:44835 graph.inbound_rtp_id = "ITTransportName1A4";
Alessio Bazzicaf7b1b952021-03-23 16:23:04836 media_info.receivers.push_back(cricket::VoiceReceiverInfo());
837 media_info.receivers[0].local_stats.push_back(cricket::SsrcReceiverInfo());
838 media_info.receivers[0].local_stats[0].ssrc = kRemoteSsrc;
839 media_info.receivers[0].codec_payload_type = recv_codec.payload_type;
840 // remote-outbound-rtp
841 if (add_remote_outbound_stats) {
Henrik Boström8dfc90f2022-09-02 07:39:29842 graph.remote_outbound_rtp_id = "ROA4";
Alessio Bazzicaf7b1b952021-03-23 16:23:04843 media_info.receivers[0].last_sender_report_timestamp_ms =
844 kRemoteOutboundStatsTimestampMs;
845 media_info.receivers[0].last_sender_report_remote_timestamp_ms =
846 kRemoteOutboundStatsRemoteTimestampMs;
847 media_info.receivers[0].sender_reports_packets_sent =
848 kRemoteOutboundStatsPacketsSent;
849 media_info.receivers[0].sender_reports_bytes_sent =
850 kRemoteOutboundStatsBytesSent;
851 media_info.receivers[0].sender_reports_reports_count =
852 kRemoteOutboundStatsReportsCount;
853 }
Alessio Bazzicaf7b1b952021-03-23 16:23:04854 // transport
Henrik Boström8dfc90f2022-09-02 07:39:29855 graph.transport_id = "TTransportName1";
Tommi19015512022-02-02 10:49:35856 pc_->AddVoiceChannel("VoiceMid", "TransportName", media_info);
Henrik Boström4e231ee2023-05-24 09:24:13857 // outbound-rtp's sender
Alessio Bazzicaf7b1b952021-03-23 16:23:04858 graph.sender = stats_->SetupLocalTrackAndSender(
859 cricket::MEDIA_TYPE_AUDIO, "LocalAudioTrackID", kLocalSsrc, false, 50);
Henrik Boström4e231ee2023-05-24 09:24:13860 // inbound-rtp's receiver
Alessio Bazzicaf7b1b952021-03-23 16:23:04861 graph.receiver = stats_->SetupRemoteTrackAndReceiver(
862 cricket::MEDIA_TYPE_AUDIO, "RemoteAudioTrackID", "RemoteStreamId",
863 kRemoteSsrc);
Alessio Bazzicaf7b1b952021-03-23 16:23:04864 // peer-connection
Henrik Boström8dfc90f2022-09-02 07:39:29865 graph.peer_connection_id = "P";
Alessio Bazzicaf7b1b952021-03-23 16:23:04866 // media-source (kind: video)
Henrik Boström8dfc90f2022-09-02 07:39:29867 graph.media_source_id = "SA" + rtc::ToString(graph.sender->AttachmentId());
Alessio Bazzicaf7b1b952021-03-23 16:23:04868
869 // Expected stats graph:
870 //
Henrik Boström4e231ee2023-05-24 09:24:13871 // media-source peer-connection
872 // ^
873 // |
874 // +--------- outbound-rtp inbound-rtp
875 // | | | |
876 // v v v v
877 // codec (send) transport codec (recv)
Alessio Bazzicaf7b1b952021-03-23 16:23:04878
879 // Verify the stats graph is set up correctly.
880 graph.full_report = stats_->GetStatsReport();
Henrik Boström4e231ee2023-05-24 09:24:13881 EXPECT_EQ(graph.full_report->size(), add_remote_outbound_stats ? 8u : 7u);
Alessio Bazzicaf7b1b952021-03-23 16:23:04882 EXPECT_TRUE(graph.full_report->Get(graph.send_codec_id));
883 EXPECT_TRUE(graph.full_report->Get(graph.recv_codec_id));
884 EXPECT_TRUE(graph.full_report->Get(graph.outbound_rtp_id));
885 EXPECT_TRUE(graph.full_report->Get(graph.inbound_rtp_id));
886 EXPECT_TRUE(graph.full_report->Get(graph.transport_id));
Alessio Bazzicaf7b1b952021-03-23 16:23:04887 EXPECT_TRUE(graph.full_report->Get(graph.peer_connection_id));
888 EXPECT_TRUE(graph.full_report->Get(graph.media_source_id));
889 // `graph.remote_outbound_rtp_id` is omitted on purpose so that expectations
890 // can be added by the caller depending on what value it sets for the
891 // `add_remote_outbound_stats` argument.
Alessio Bazzicaf7b1b952021-03-23 16:23:04892 const auto& outbound_rtp = graph.full_report->Get(graph.outbound_rtp_id)
Philipp Hancke1f98b462023-03-07 08:53:59893 ->cast_to<RTCOutboundRtpStreamStats>();
Alessio Bazzicaf7b1b952021-03-23 16:23:04894 EXPECT_EQ(*outbound_rtp.media_source_id, graph.media_source_id);
895 EXPECT_EQ(*outbound_rtp.codec_id, graph.send_codec_id);
Alessio Bazzicaf7b1b952021-03-23 16:23:04896 EXPECT_EQ(*outbound_rtp.transport_id, graph.transport_id);
Harald Alvestrand2f553702023-03-07 10:10:03897 EXPECT_TRUE(graph.full_report->Get(graph.inbound_rtp_id));
898 // We can't use ASSERT in a function with a return value.
899 if (!graph.full_report->Get(graph.inbound_rtp_id)) {
900 return graph;
901 }
Alessio Bazzicaf7b1b952021-03-23 16:23:04902 const auto& inbound_rtp = graph.full_report->Get(graph.inbound_rtp_id)
Philipp Hancke1f98b462023-03-07 08:53:59903 ->cast_to<RTCInboundRtpStreamStats>();
Alessio Bazzicaf7b1b952021-03-23 16:23:04904 EXPECT_EQ(*inbound_rtp.codec_id, graph.recv_codec_id);
Alessio Bazzicaf7b1b952021-03-23 16:23:04905 EXPECT_EQ(*inbound_rtp.transport_id, graph.transport_id);
906
907 return graph;
908 }
909
hbosc82f2e12016-09-05 08:36:50910 protected:
Steve Anton5b387312018-02-03 00:00:20911 rtc::ScopedFakeClock fake_clock_;
Niels Möller83830f32022-05-20 07:12:57912 rtc::AutoThread main_thread_;
Steve Anton5b387312018-02-03 00:00:20913 rtc::scoped_refptr<FakePeerConnectionForStats> pc_;
914 std::unique_ptr<RTCStatsCollectorWrapper> stats_;
Tommifaf33872023-03-16 08:25:29915 std::unique_ptr<FakeDataChannelController> data_channel_controller_;
hbosc82f2e12016-09-05 08:36:50916};
917
918TEST_F(RTCStatsCollectorTest, SingleCallback) {
919 rtc::scoped_refptr<const RTCStatsReport> result;
Steve Anton5b387312018-02-03 00:00:20920 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&result));
Niels Möllerafb246b2022-04-20 12:26:50921 EXPECT_TRUE_WAIT(result != nullptr, kGetStatsReportTimeoutMs);
hbosc82f2e12016-09-05 08:36:50922}
923
924TEST_F(RTCStatsCollectorTest, MultipleCallbacks) {
Steve Anton5b387312018-02-03 00:00:20925 rtc::scoped_refptr<const RTCStatsReport> a, b, c;
926 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&a));
927 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&b));
928 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&c));
Niels Möllerafb246b2022-04-20 12:26:50929 EXPECT_TRUE_WAIT(a != nullptr, kGetStatsReportTimeoutMs);
930 EXPECT_TRUE_WAIT(b != nullptr, kGetStatsReportTimeoutMs);
931 EXPECT_TRUE_WAIT(c != nullptr, kGetStatsReportTimeoutMs);
Steve Anton5b387312018-02-03 00:00:20932
hbosc82f2e12016-09-05 08:36:50933 EXPECT_EQ(a.get(), b.get());
934 EXPECT_EQ(b.get(), c.get());
935}
936
937TEST_F(RTCStatsCollectorTest, CachedStatsReports) {
Artem Titov880fa812021-07-30 20:30:23938 // Caching should ensure `a` and `b` are the same report.
Steve Anton5b387312018-02-03 00:00:20939 rtc::scoped_refptr<const RTCStatsReport> a = stats_->GetStatsReport();
940 rtc::scoped_refptr<const RTCStatsReport> b = stats_->GetStatsReport();
hbosd565b732016-08-30 21:04:35941 EXPECT_EQ(a.get(), b.get());
942 // Invalidate cache by clearing it.
Steve Anton5b387312018-02-03 00:00:20943 stats_->stats_collector()->ClearCachedStatsReport();
944 rtc::scoped_refptr<const RTCStatsReport> c = stats_->GetStatsReport();
hbosd565b732016-08-30 21:04:35945 EXPECT_NE(b.get(), c.get());
946 // Invalidate cache by advancing time.
Danil Chapovalov0c626af2020-02-10 10:16:00947 fake_clock_.AdvanceTime(TimeDelta::Millis(51));
Steve Anton5b387312018-02-03 00:00:20948 rtc::scoped_refptr<const RTCStatsReport> d = stats_->GetStatsReport();
hbosd565b732016-08-30 21:04:35949 EXPECT_TRUE(d);
950 EXPECT_NE(c.get(), d.get());
951}
952
hbosc82f2e12016-09-05 08:36:50953TEST_F(RTCStatsCollectorTest, MultipleCallbacksWithInvalidatedCacheInBetween) {
Steve Anton5b387312018-02-03 00:00:20954 rtc::scoped_refptr<const RTCStatsReport> a, b, c;
955 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&a));
956 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&b));
hbosc82f2e12016-09-05 08:36:50957 // Cache is invalidated after 50 ms.
Danil Chapovalov0c626af2020-02-10 10:16:00958 fake_clock_.AdvanceTime(TimeDelta::Millis(51));
Steve Anton5b387312018-02-03 00:00:20959 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&c));
Niels Möllerafb246b2022-04-20 12:26:50960 EXPECT_TRUE_WAIT(a != nullptr, kGetStatsReportTimeoutMs);
961 EXPECT_TRUE_WAIT(b != nullptr, kGetStatsReportTimeoutMs);
962 EXPECT_TRUE_WAIT(c != nullptr, kGetStatsReportTimeoutMs);
hbosc82f2e12016-09-05 08:36:50963 EXPECT_EQ(a.get(), b.get());
Artem Titov880fa812021-07-30 20:30:23964 // The act of doing `AdvanceTime` processes all messages. If this was not the
965 // case we might not require `c` to be fresher than `b`.
hbosc82f2e12016-09-05 08:36:50966 EXPECT_NE(c.get(), b.get());
967}
968
Harald Alvestrand910cdc22020-01-09 11:58:23969TEST_F(RTCStatsCollectorTest, ToJsonProducesParseableJson) {
970 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
971 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
972 std::string json_format = report->ToJson();
Mirko Bonadeie99f6872021-06-24 13:24:59973
974 Json::CharReaderBuilder builder;
Harald Alvestrand910cdc22020-01-09 11:58:23975 Json::Value json_value;
Mirko Bonadeie99f6872021-06-24 13:24:59976 std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
977 ASSERT_TRUE(reader->parse(json_format.c_str(),
978 json_format.c_str() + json_format.size(),
979 &json_value, nullptr));
980
Harald Alvestrand910cdc22020-01-09 11:58:23981 // A very brief sanity check on the result.
982 EXPECT_EQ(report->size(), json_value.size());
983}
984
hbos6ab97ce02016-10-03 21:16:56985TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsSingle) {
Steve Anton5b387312018-02-03 00:00:20986 const char kTransportName[] = "transport";
987
988 pc_->AddVoiceChannel("audio", kTransportName);
989
hbos6ab97ce02016-10-03 21:16:56990 std::unique_ptr<CertificateInfo> local_certinfo =
991 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 13:03:05992 std::vector<std::string>({"(local) single certificate"}));
Steve Anton5b387312018-02-03 00:00:20993 pc_->SetLocalCertificate(kTransportName, local_certinfo->certificate);
994
hbos6ab97ce02016-10-03 21:16:56995 std::unique_ptr<CertificateInfo> remote_certinfo =
996 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 13:03:05997 std::vector<std::string>({"(remote) single certificate"}));
Taylor Brandstetterc3928662018-02-23 21:04:51998 pc_->SetRemoteCertChain(
Benjamin Wright6c6c9df2018-10-25 08:16:26999 kTransportName,
1000 remote_certinfo->certificate->GetSSLCertificateChain().Clone());
hbos6ab97ce02016-10-03 21:16:561001
Steve Anton5b387312018-02-03 00:00:201002 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos6ab97ce02016-10-03 21:16:561003
hbos23368e12016-12-21 12:29:171004 ExpectReportContainsCertificateInfo(report, *local_certinfo);
1005 ExpectReportContainsCertificateInfo(report, *remote_certinfo);
hbos6ab97ce02016-10-03 21:16:561006}
1007
Henrik Boströmda6297d2022-09-19 09:33:231008// These SSRC collisions are legal.
1009TEST_F(RTCStatsCollectorTest, ValidSsrcCollisionDoesNotCrash) {
1010 // BUNDLE audio/video inbound/outbound. Unique SSRCs needed within the BUNDLE.
1011 cricket::VoiceMediaInfo mid1_info;
1012 mid1_info.receivers.emplace_back();
1013 mid1_info.receivers[0].add_ssrc(1);
1014 mid1_info.senders.emplace_back();
1015 mid1_info.senders[0].add_ssrc(2);
1016 pc_->AddVoiceChannel("Mid1", "Transport1", mid1_info);
1017 cricket::VideoMediaInfo mid2_info;
1018 mid2_info.receivers.emplace_back();
1019 mid2_info.receivers[0].add_ssrc(3);
1020 mid2_info.senders.emplace_back();
1021 mid2_info.senders[0].add_ssrc(4);
1022 pc_->AddVideoChannel("Mid2", "Transport1", mid2_info);
1023 // Now create a second BUNDLE group with SSRCs colliding with the first group
1024 // (but again no collisions within the group).
1025 cricket::VoiceMediaInfo mid3_info;
1026 mid3_info.receivers.emplace_back();
1027 mid3_info.receivers[0].add_ssrc(1);
1028 mid3_info.senders.emplace_back();
1029 mid3_info.senders[0].add_ssrc(2);
1030 pc_->AddVoiceChannel("Mid3", "Transport2", mid3_info);
1031 cricket::VideoMediaInfo mid4_info;
1032 mid4_info.receivers.emplace_back();
1033 mid4_info.receivers[0].add_ssrc(3);
1034 mid4_info.senders.emplace_back();
1035 mid4_info.senders[0].add_ssrc(4);
1036 pc_->AddVideoChannel("Mid4", "Transport2", mid4_info);
1037
1038 // This should not crash (https://crbug.com/1361612).
1039 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Philipp Hancke1f98b462023-03-07 08:53:591040 auto inbound_rtps = report->GetStatsOfType<RTCInboundRtpStreamStats>();
1041 auto outbound_rtps = report->GetStatsOfType<RTCOutboundRtpStreamStats>();
Henrik Boströmb43e3bb2022-09-26 10:36:441042 EXPECT_EQ(inbound_rtps.size(), 4u);
1043 EXPECT_EQ(outbound_rtps.size(), 4u);
Henrik Boströmda6297d2022-09-19 09:33:231044}
1045
1046// These SSRC collisions are illegal, so it is not clear if this setup can
1047// happen even when talking to a malicious endpoint, but simulate illegal SSRC
1048// collisions just to make sure we don't crash in even the most extreme cases.
1049TEST_F(RTCStatsCollectorTest, InvalidSsrcCollisionDoesNotCrash) {
1050 // One SSRC to rule them all.
1051 cricket::VoiceMediaInfo mid1_info;
1052 mid1_info.receivers.emplace_back();
1053 mid1_info.receivers[0].add_ssrc(1);
1054 mid1_info.senders.emplace_back();
1055 mid1_info.senders[0].add_ssrc(1);
1056 pc_->AddVoiceChannel("Mid1", "BundledTransport", mid1_info);
1057 cricket::VideoMediaInfo mid2_info;
1058 mid2_info.receivers.emplace_back();
1059 mid2_info.receivers[0].add_ssrc(1);
1060 mid2_info.senders.emplace_back();
1061 mid2_info.senders[0].add_ssrc(1);
1062 pc_->AddVideoChannel("Mid2", "BundledTransport", mid2_info);
1063 cricket::VoiceMediaInfo mid3_info;
1064 mid3_info.receivers.emplace_back();
1065 mid3_info.receivers[0].add_ssrc(1);
1066 mid3_info.senders.emplace_back();
1067 mid3_info.senders[0].add_ssrc(1);
1068 pc_->AddVoiceChannel("Mid3", "BundledTransport", mid3_info);
1069 cricket::VideoMediaInfo mid4_info;
1070 mid4_info.receivers.emplace_back();
1071 mid4_info.receivers[0].add_ssrc(1);
1072 mid4_info.senders.emplace_back();
1073 mid4_info.senders[0].add_ssrc(1);
1074 pc_->AddVideoChannel("Mid4", "BundledTransport", mid4_info);
1075
1076 // This should not crash (https://crbug.com/1361612).
1077 stats_->GetStatsReport();
1078 // Because this setup is illegal, there is no "right answer" to how the report
1079 // should look. We only care about not crashing.
1080}
1081
Henrik Boström31c373b2022-09-26 12:56:211082TEST_F(RTCStatsCollectorTest, CollectRTCCodecStatsOnlyIfReferenced) {
hbos0adb8282016-11-23 10:32:061083 // Audio
1084 cricket::VoiceMediaInfo voice_media_info;
1085
1086 RtpCodecParameters inbound_audio_codec;
1087 inbound_audio_codec.payload_type = 1;
deadbeefe702b302017-02-04 20:09:011088 inbound_audio_codec.kind = cricket::MEDIA_TYPE_AUDIO;
1089 inbound_audio_codec.name = "opus";
Oskar Sundbomcbc71b22017-11-16 09:56:071090 inbound_audio_codec.clock_rate = 1337;
Johannes Kron72d69152020-02-10 13:05:551091 inbound_audio_codec.num_channels = 1;
1092 inbound_audio_codec.parameters = {{"minptime", "10"}, {"useinbandfec", "1"}};
hbos0adb8282016-11-23 10:32:061093 voice_media_info.receive_codecs.insert(
1094 std::make_pair(inbound_audio_codec.payload_type, inbound_audio_codec));
1095
1096 RtpCodecParameters outbound_audio_codec;
1097 outbound_audio_codec.payload_type = 2;
deadbeefe702b302017-02-04 20:09:011098 outbound_audio_codec.kind = cricket::MEDIA_TYPE_AUDIO;
1099 outbound_audio_codec.name = "isac";
Oskar Sundbomcbc71b22017-11-16 09:56:071100 outbound_audio_codec.clock_rate = 1338;
Johannes Kron72d69152020-02-10 13:05:551101 outbound_audio_codec.num_channels = 2;
hbos0adb8282016-11-23 10:32:061102 voice_media_info.send_codecs.insert(
1103 std::make_pair(outbound_audio_codec.payload_type, outbound_audio_codec));
1104
hbos0adb8282016-11-23 10:32:061105 // Video
1106 cricket::VideoMediaInfo video_media_info;
1107
1108 RtpCodecParameters inbound_video_codec;
1109 inbound_video_codec.payload_type = 3;
deadbeefe702b302017-02-04 20:09:011110 inbound_video_codec.kind = cricket::MEDIA_TYPE_VIDEO;
1111 inbound_video_codec.name = "H264";
Oskar Sundbomcbc71b22017-11-16 09:56:071112 inbound_video_codec.clock_rate = 1339;
Johannes Kron72d69152020-02-10 13:05:551113 inbound_video_codec.parameters = {{"level-asymmetry-allowed", "1"},
1114 {"packetization-mode", "1"},
1115 {"profile-level-id", "42001f"}};
hbos0adb8282016-11-23 10:32:061116 video_media_info.receive_codecs.insert(
1117 std::make_pair(inbound_video_codec.payload_type, inbound_video_codec));
1118
1119 RtpCodecParameters outbound_video_codec;
1120 outbound_video_codec.payload_type = 4;
deadbeefe702b302017-02-04 20:09:011121 outbound_video_codec.kind = cricket::MEDIA_TYPE_VIDEO;
1122 outbound_video_codec.name = "VP8";
Oskar Sundbomcbc71b22017-11-16 09:56:071123 outbound_video_codec.clock_rate = 1340;
hbos0adb8282016-11-23 10:32:061124 video_media_info.send_codecs.insert(
1125 std::make_pair(outbound_video_codec.payload_type, outbound_video_codec));
1126
Henrik Boström31c373b2022-09-26 12:56:211127 // Ensure the above codecs are referenced.
1128 cricket::VoiceReceiverInfo inbound_audio_info;
1129 inbound_audio_info.add_ssrc(10);
1130 inbound_audio_info.codec_payload_type = 1;
1131 voice_media_info.receivers.push_back(inbound_audio_info);
1132
1133 cricket::VoiceSenderInfo outbound_audio_info;
1134 outbound_audio_info.add_ssrc(20);
1135 outbound_audio_info.codec_payload_type = 2;
1136 voice_media_info.senders.push_back(outbound_audio_info);
1137
1138 cricket::VideoReceiverInfo inbound_video_info;
1139 inbound_video_info.add_ssrc(30);
1140 inbound_video_info.codec_payload_type = 3;
1141 video_media_info.receivers.push_back(inbound_video_info);
1142
1143 cricket::VideoSenderInfo outbound_video_info;
1144 outbound_video_info.add_ssrc(40);
1145 outbound_video_info.codec_payload_type = 4;
1146 video_media_info.senders.push_back(outbound_video_info);
1147
Harald Alvestrand2f553702023-03-07 10:10:031148 auto audio_channels =
Henrik Boström31c373b2022-09-26 12:56:211149 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Harald Alvestrand2f553702023-03-07 10:10:031150 auto video_channels =
Henrik Boström31c373b2022-09-26 12:56:211151 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
hbos0adb8282016-11-23 10:32:061152
Steve Anton5b387312018-02-03 00:00:201153 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos0adb8282016-11-23 10:32:061154
Henrik Boströmb2be3922022-09-02 07:37:081155 RTCCodecStats expected_inbound_audio_codec(
Philipp Hanckeb81823a2023-01-04 14:17:421156 "CITTransportName1_1_minptime=10;useinbandfec=1", report->timestamp());
hbos0adb8282016-11-23 10:32:061157 expected_inbound_audio_codec.payload_type = 1;
hbos13f54b22017-02-28 14:56:041158 expected_inbound_audio_codec.mime_type = "audio/opus";
hbos0adb8282016-11-23 10:32:061159 expected_inbound_audio_codec.clock_rate = 1337;
Johannes Kron72d69152020-02-10 13:05:551160 expected_inbound_audio_codec.channels = 1;
1161 expected_inbound_audio_codec.sdp_fmtp_line = "minptime=10;useinbandfec=1";
Henrik Boström8dfc90f2022-09-02 07:39:291162 expected_inbound_audio_codec.transport_id = "TTransportName1";
hbos0adb8282016-11-23 10:32:061163
Henrik Boström8dfc90f2022-09-02 07:39:291164 RTCCodecStats expected_outbound_audio_codec("COTTransportName1_2",
Philipp Hanckeb81823a2023-01-04 14:17:421165 report->timestamp());
hbos0adb8282016-11-23 10:32:061166 expected_outbound_audio_codec.payload_type = 2;
hbos13f54b22017-02-28 14:56:041167 expected_outbound_audio_codec.mime_type = "audio/isac";
hbos0adb8282016-11-23 10:32:061168 expected_outbound_audio_codec.clock_rate = 1338;
Johannes Kron72d69152020-02-10 13:05:551169 expected_outbound_audio_codec.channels = 2;
Henrik Boström8dfc90f2022-09-02 07:39:291170 expected_outbound_audio_codec.transport_id = "TTransportName1";
hbos0adb8282016-11-23 10:32:061171
Henrik Boströmb2be3922022-09-02 07:37:081172 RTCCodecStats expected_inbound_video_codec(
Henrik Boström8dfc90f2022-09-02 07:39:291173 "CITTransportName1_3_level-asymmetry-allowed=1;"
Henrik Boströmb2be3922022-09-02 07:37:081174 "packetization-mode=1;profile-level-id=42001f",
Philipp Hanckeb81823a2023-01-04 14:17:421175 report->timestamp());
hbos0adb8282016-11-23 10:32:061176 expected_inbound_video_codec.payload_type = 3;
hbos13f54b22017-02-28 14:56:041177 expected_inbound_video_codec.mime_type = "video/H264";
hbos0adb8282016-11-23 10:32:061178 expected_inbound_video_codec.clock_rate = 1339;
Johannes Kron72d69152020-02-10 13:05:551179 expected_inbound_video_codec.sdp_fmtp_line =
1180 "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f";
Henrik Boström8dfc90f2022-09-02 07:39:291181 expected_inbound_video_codec.transport_id = "TTransportName1";
hbos0adb8282016-11-23 10:32:061182
Henrik Boström8dfc90f2022-09-02 07:39:291183 RTCCodecStats expected_outbound_video_codec("COTTransportName1_4",
Philipp Hanckeb81823a2023-01-04 14:17:421184 report->timestamp());
hbos0adb8282016-11-23 10:32:061185 expected_outbound_video_codec.payload_type = 4;
hbos13f54b22017-02-28 14:56:041186 expected_outbound_video_codec.mime_type = "video/VP8";
hbos0adb8282016-11-23 10:32:061187 expected_outbound_video_codec.clock_rate = 1340;
Henrik Boström8dfc90f2022-09-02 07:39:291188 expected_outbound_video_codec.transport_id = "TTransportName1";
hbos0adb8282016-11-23 10:32:061189
nissec8ee8822017-01-18 15:20:551190 ASSERT_TRUE(report->Get(expected_inbound_audio_codec.id()));
Yves Gerey665174f2018-06-19 13:03:051191 EXPECT_EQ(
1192 expected_inbound_audio_codec,
1193 report->Get(expected_inbound_audio_codec.id())->cast_to<RTCCodecStats>());
hbos0adb8282016-11-23 10:32:061194
nissec8ee8822017-01-18 15:20:551195 ASSERT_TRUE(report->Get(expected_outbound_audio_codec.id()));
hbos0adb8282016-11-23 10:32:061196 EXPECT_EQ(expected_outbound_audio_codec,
Yves Gerey665174f2018-06-19 13:03:051197 report->Get(expected_outbound_audio_codec.id())
1198 ->cast_to<RTCCodecStats>());
hbos0adb8282016-11-23 10:32:061199
nissec8ee8822017-01-18 15:20:551200 ASSERT_TRUE(report->Get(expected_inbound_video_codec.id()));
Yves Gerey665174f2018-06-19 13:03:051201 EXPECT_EQ(
1202 expected_inbound_video_codec,
1203 report->Get(expected_inbound_video_codec.id())->cast_to<RTCCodecStats>());
hbos0adb8282016-11-23 10:32:061204
nissec8ee8822017-01-18 15:20:551205 ASSERT_TRUE(report->Get(expected_outbound_video_codec.id()));
hbos0adb8282016-11-23 10:32:061206 EXPECT_EQ(expected_outbound_video_codec,
Yves Gerey665174f2018-06-19 13:03:051207 report->Get(expected_outbound_video_codec.id())
1208 ->cast_to<RTCCodecStats>());
Henrik Boström31c373b2022-09-26 12:56:211209
1210 // Now remove all the RTP streams such that there are no live codecId
1211 // references to the codecs, this should result in none of the RTCCodecStats
1212 // being exposed, despite `send_codecs` and `receive_codecs` still being set.
1213 voice_media_info.senders.clear();
1214 voice_media_info.receivers.clear();
Harald Alvestrand2f553702023-03-07 10:10:031215 audio_channels.first->SetStats(voice_media_info);
1216 audio_channels.second->SetStats(voice_media_info);
Henrik Boström31c373b2022-09-26 12:56:211217 video_media_info.senders.clear();
1218 video_media_info.receivers.clear();
Harald Alvestrand2f553702023-03-07 10:10:031219 video_channels.first->SetStats(video_media_info);
1220 video_channels.second->SetStats(video_media_info);
Henrik Boström31c373b2022-09-26 12:56:211221 stats_->stats_collector()->ClearCachedStatsReport();
1222 report = stats_->GetStatsReport();
1223 EXPECT_FALSE(report->Get(expected_inbound_audio_codec.id()));
1224 EXPECT_FALSE(report->Get(expected_outbound_audio_codec.id()));
1225 EXPECT_FALSE(report->Get(expected_inbound_video_codec.id()));
1226 EXPECT_FALSE(report->Get(expected_outbound_video_codec.id()));
hbos0adb8282016-11-23 10:32:061227}
1228
Henrik Boströmb2be3922022-09-02 07:37:081229TEST_F(RTCStatsCollectorTest, CodecStatsAreCollectedPerTransport) {
1230 // PT=10
1231 RtpCodecParameters outbound_codec_pt10;
1232 outbound_codec_pt10.payload_type = 10;
1233 outbound_codec_pt10.kind = cricket::MEDIA_TYPE_VIDEO;
1234 outbound_codec_pt10.name = "VP8";
1235 outbound_codec_pt10.clock_rate = 9000;
1236
1237 // PT=11
1238 RtpCodecParameters outbound_codec_pt11;
1239 outbound_codec_pt11.payload_type = 11;
1240 outbound_codec_pt11.kind = cricket::MEDIA_TYPE_VIDEO;
1241 outbound_codec_pt11.name = "VP8";
1242 outbound_codec_pt11.clock_rate = 9000;
1243
Henrik Boström31c373b2022-09-26 12:56:211244 // Insert codecs into `send_codecs` and ensure the PTs are referenced by RTP
1245 // streams.
Henrik Boströmb2be3922022-09-02 07:37:081246 cricket::VideoMediaInfo info_pt10;
1247 info_pt10.send_codecs.insert(
1248 std::make_pair(outbound_codec_pt10.payload_type, outbound_codec_pt10));
Henrik Boström31c373b2022-09-26 12:56:211249 info_pt10.senders.emplace_back();
1250 info_pt10.senders[0].add_ssrc(42);
1251 info_pt10.senders[0].codec_payload_type = outbound_codec_pt10.payload_type;
1252
Henrik Boströmb2be3922022-09-02 07:37:081253 cricket::VideoMediaInfo info_pt11;
1254 info_pt11.send_codecs.insert(
1255 std::make_pair(outbound_codec_pt11.payload_type, outbound_codec_pt11));
Henrik Boström31c373b2022-09-26 12:56:211256 info_pt11.senders.emplace_back();
1257 info_pt11.senders[0].add_ssrc(43);
1258 info_pt11.senders[0].codec_payload_type = outbound_codec_pt11.payload_type;
1259
Henrik Boströmb2be3922022-09-02 07:37:081260 cricket::VideoMediaInfo info_pt10_pt11;
1261 info_pt10_pt11.send_codecs.insert(
1262 std::make_pair(outbound_codec_pt10.payload_type, outbound_codec_pt10));
1263 info_pt10_pt11.send_codecs.insert(
1264 std::make_pair(outbound_codec_pt11.payload_type, outbound_codec_pt11));
Henrik Boström31c373b2022-09-26 12:56:211265 info_pt10_pt11.senders.emplace_back();
1266 info_pt10_pt11.senders[0].add_ssrc(44);
1267 info_pt10_pt11.senders[0].codec_payload_type =
1268 outbound_codec_pt10.payload_type;
1269 info_pt10_pt11.senders.emplace_back();
1270 info_pt10_pt11.senders[1].add_ssrc(45);
1271 info_pt10_pt11.senders[1].codec_payload_type =
1272 outbound_codec_pt11.payload_type;
Henrik Boströmb2be3922022-09-02 07:37:081273
1274 // First two mids contain subsets, the third one contains all PTs.
1275 pc_->AddVideoChannel("Mid1", "FirstTransport", info_pt10);
1276 pc_->AddVideoChannel("Mid2", "FirstTransport", info_pt11);
1277 pc_->AddVideoChannel("Mid3", "FirstTransport", info_pt10_pt11);
1278
1279 // There should be no duplicate codecs because all codec references are on the
1280 // same transport.
1281 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1282 auto codec_stats = report->GetStatsOfType<RTCCodecStats>();
1283 EXPECT_EQ(codec_stats.size(), 2u);
1284
1285 // If a second transport is added with the same PT information, this does
1286 // count as different codec objects.
1287 pc_->AddVideoChannel("Mid4", "SecondTransport", info_pt10_pt11);
1288 stats_->stats_collector()->ClearCachedStatsReport();
1289 report = stats_->GetStatsReport();
1290 codec_stats = report->GetStatsOfType<RTCCodecStats>();
1291 EXPECT_EQ(codec_stats.size(), 4u);
1292}
1293
1294TEST_F(RTCStatsCollectorTest, SamePayloadTypeButDifferentFmtpLines) {
1295 // PT=111, useinbandfec=0
1296 RtpCodecParameters inbound_codec_pt111_nofec;
1297 inbound_codec_pt111_nofec.payload_type = 111;
1298 inbound_codec_pt111_nofec.kind = cricket::MEDIA_TYPE_AUDIO;
1299 inbound_codec_pt111_nofec.name = "opus";
1300 inbound_codec_pt111_nofec.clock_rate = 48000;
1301 inbound_codec_pt111_nofec.parameters.insert(
1302 std::make_pair("useinbandfec", "0"));
1303
1304 // PT=111, useinbandfec=1
1305 RtpCodecParameters inbound_codec_pt111_fec;
1306 inbound_codec_pt111_fec.payload_type = 111;
1307 inbound_codec_pt111_fec.kind = cricket::MEDIA_TYPE_AUDIO;
1308 inbound_codec_pt111_fec.name = "opus";
1309 inbound_codec_pt111_fec.clock_rate = 48000;
1310 inbound_codec_pt111_fec.parameters.insert(
1311 std::make_pair("useinbandfec", "1"));
1312
1313 cricket::VideoMediaInfo info_nofec;
Henrik Boström31c373b2022-09-26 12:56:211314 info_nofec.receive_codecs.insert(std::make_pair(
Henrik Boströmb2be3922022-09-02 07:37:081315 inbound_codec_pt111_nofec.payload_type, inbound_codec_pt111_nofec));
Henrik Boström31c373b2022-09-26 12:56:211316 info_nofec.receivers.emplace_back();
1317 info_nofec.receivers[0].add_ssrc(123);
1318 info_nofec.receivers[0].codec_payload_type =
1319 inbound_codec_pt111_nofec.payload_type;
Henrik Boströmb2be3922022-09-02 07:37:081320 cricket::VideoMediaInfo info_fec;
Henrik Boström31c373b2022-09-26 12:56:211321 info_fec.receive_codecs.insert(std::make_pair(
Henrik Boströmb2be3922022-09-02 07:37:081322 inbound_codec_pt111_fec.payload_type, inbound_codec_pt111_fec));
Henrik Boström31c373b2022-09-26 12:56:211323 info_fec.receivers.emplace_back();
1324 info_fec.receivers[0].add_ssrc(321);
1325 info_fec.receivers[0].codec_payload_type =
1326 inbound_codec_pt111_fec.payload_type;
Henrik Boströmb2be3922022-09-02 07:37:081327
1328 // First two mids contain subsets, the third one contains all PTs.
1329 pc_->AddVideoChannel("Mid1", "BundledTransport", info_nofec);
1330 pc_->AddVideoChannel("Mid2", "BundledTransport", info_fec);
1331
1332 // Despite having the same PT we should see two codec stats because their FMTP
1333 // lines are different.
1334 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1335 auto codec_stats = report->GetStatsOfType<RTCCodecStats>();
1336 EXPECT_EQ(codec_stats.size(), 2u);
1337
Henrik Boström31c373b2022-09-26 12:56:211338 // Ensure SSRC uniqueness before the next AddVideoChannel() call. SSRCs need
1339 // to be unique on different m= sections when using BUNDLE.
1340 info_nofec.receivers[0].local_stats[0].ssrc = 12;
1341 info_fec.receivers[0].local_stats[0].ssrc = 21;
Henrik Boströmb2be3922022-09-02 07:37:081342 // Adding more m= sections that does have the same FMTP lines does not result
1343 // in duplicates.
1344 pc_->AddVideoChannel("Mid3", "BundledTransport", info_nofec);
1345 pc_->AddVideoChannel("Mid4", "BundledTransport", info_fec);
1346 stats_->stats_collector()->ClearCachedStatsReport();
1347 report = stats_->GetStatsReport();
1348 codec_stats = report->GetStatsOfType<RTCCodecStats>();
1349 EXPECT_EQ(codec_stats.size(), 2u);
1350
1351 // Same FMTP line but a different PT does count as a new codec.
1352 // PT=112, useinbandfec=1
1353 RtpCodecParameters inbound_codec_pt112_fec;
1354 inbound_codec_pt112_fec.payload_type = 112;
1355 inbound_codec_pt112_fec.kind = cricket::MEDIA_TYPE_AUDIO;
1356 inbound_codec_pt112_fec.name = "opus";
1357 inbound_codec_pt112_fec.clock_rate = 48000;
1358 inbound_codec_pt112_fec.parameters.insert(
1359 std::make_pair("useinbandfec", "1"));
1360 cricket::VideoMediaInfo info_fec_pt112;
Henrik Boström31c373b2022-09-26 12:56:211361 info_fec_pt112.receive_codecs.insert(std::make_pair(
Henrik Boströmb2be3922022-09-02 07:37:081362 inbound_codec_pt112_fec.payload_type, inbound_codec_pt112_fec));
Henrik Boström31c373b2022-09-26 12:56:211363 info_fec_pt112.receivers.emplace_back();
1364 info_fec_pt112.receivers[0].add_ssrc(112);
1365 info_fec_pt112.receivers[0].codec_payload_type =
1366 inbound_codec_pt112_fec.payload_type;
Henrik Boströmb2be3922022-09-02 07:37:081367 pc_->AddVideoChannel("Mid5", "BundledTransport", info_fec_pt112);
1368 stats_->stats_collector()->ClearCachedStatsReport();
1369 report = stats_->GetStatsReport();
1370 codec_stats = report->GetStatsOfType<RTCCodecStats>();
1371 EXPECT_EQ(codec_stats.size(), 3u);
1372}
1373
hbos6ab97ce02016-10-03 21:16:561374TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsMultiple) {
Steve Anton5b387312018-02-03 00:00:201375 const char kAudioTransport[] = "audio";
1376 const char kVideoTransport[] = "video";
1377
1378 pc_->AddVoiceChannel("audio", kAudioTransport);
Tommi19015512022-02-02 10:49:351379
hbos6ab97ce02016-10-03 21:16:561380 std::unique_ptr<CertificateInfo> audio_local_certinfo =
1381 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 13:03:051382 std::vector<std::string>({"(local) audio"}));
Steve Anton5b387312018-02-03 00:00:201383 pc_->SetLocalCertificate(kAudioTransport, audio_local_certinfo->certificate);
hbos6ab97ce02016-10-03 21:16:561384 std::unique_ptr<CertificateInfo> audio_remote_certinfo =
1385 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 13:03:051386 std::vector<std::string>({"(remote) audio"}));
Taylor Brandstetterc3928662018-02-23 21:04:511387 pc_->SetRemoteCertChain(
1388 kAudioTransport,
Benjamin Wright6c6c9df2018-10-25 08:16:261389 audio_remote_certinfo->certificate->GetSSLCertificateChain().Clone());
hbos6ab97ce02016-10-03 21:16:561390
Steve Anton5b387312018-02-03 00:00:201391 pc_->AddVideoChannel("video", kVideoTransport);
hbos6ab97ce02016-10-03 21:16:561392 std::unique_ptr<CertificateInfo> video_local_certinfo =
1393 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 13:03:051394 std::vector<std::string>({"(local) video"}));
Steve Anton5b387312018-02-03 00:00:201395 pc_->SetLocalCertificate(kVideoTransport, video_local_certinfo->certificate);
hbos6ab97ce02016-10-03 21:16:561396 std::unique_ptr<CertificateInfo> video_remote_certinfo =
1397 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 13:03:051398 std::vector<std::string>({"(remote) video"}));
Taylor Brandstetterc3928662018-02-23 21:04:511399 pc_->SetRemoteCertChain(
1400 kVideoTransport,
Benjamin Wright6c6c9df2018-10-25 08:16:261401 video_remote_certinfo->certificate->GetSSLCertificateChain().Clone());
hbos6ab97ce02016-10-03 21:16:561402
Steve Anton5b387312018-02-03 00:00:201403 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos23368e12016-12-21 12:29:171404 ExpectReportContainsCertificateInfo(report, *audio_local_certinfo);
1405 ExpectReportContainsCertificateInfo(report, *audio_remote_certinfo);
1406 ExpectReportContainsCertificateInfo(report, *video_local_certinfo);
1407 ExpectReportContainsCertificateInfo(report, *video_remote_certinfo);
hbos6ab97ce02016-10-03 21:16:561408}
1409
1410TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsChain) {
Steve Anton5b387312018-02-03 00:00:201411 const char kTransportName[] = "transport";
1412
1413 pc_->AddVoiceChannel("audio", kTransportName);
1414
hbos6ab97ce02016-10-03 21:16:561415 std::unique_ptr<CertificateInfo> local_certinfo =
Steve Anton5b387312018-02-03 00:00:201416 CreateFakeCertificateAndInfoFromDers(
1417 {"(local) this", "(local) is", "(local) a", "(local) chain"});
1418 pc_->SetLocalCertificate(kTransportName, local_certinfo->certificate);
1419
hbos6ab97ce02016-10-03 21:16:561420 std::unique_ptr<CertificateInfo> remote_certinfo =
Steve Anton5b387312018-02-03 00:00:201421 CreateFakeCertificateAndInfoFromDers({"(remote) this", "(remote) is",
1422 "(remote) another",
1423 "(remote) chain"});
Taylor Brandstetterc3928662018-02-23 21:04:511424 pc_->SetRemoteCertChain(
Benjamin Wright6c6c9df2018-10-25 08:16:261425 kTransportName,
1426 remote_certinfo->certificate->GetSSLCertificateChain().Clone());
hbos6ab97ce02016-10-03 21:16:561427
Steve Anton5b387312018-02-03 00:00:201428 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos23368e12016-12-21 12:29:171429 ExpectReportContainsCertificateInfo(report, *local_certinfo);
1430 ExpectReportContainsCertificateInfo(report, *remote_certinfo);
hbos6ab97ce02016-10-03 21:16:561431}
1432
Henrik Boström69d23c92022-09-26 12:13:171433TEST_F(RTCStatsCollectorTest, CertificateStatsCache) {
1434 const char kTransportName[] = "transport";
1435 rtc::ScopedFakeClock fake_clock;
1436
1437 pc_->AddVoiceChannel("audio", kTransportName);
1438
1439 // Set local and remote cerificates.
1440 std::unique_ptr<CertificateInfo> initial_local_certinfo =
1441 CreateFakeCertificateAndInfoFromDers({"LocalCertA", "LocalCertB"});
1442 pc_->SetLocalCertificate(kTransportName, initial_local_certinfo->certificate);
1443 std::unique_ptr<CertificateInfo> initial_remote_certinfo =
1444 CreateFakeCertificateAndInfoFromDers({"RemoteCertA", "RemoteCertB"});
1445 pc_->SetRemoteCertChain(
1446 kTransportName,
1447 initial_remote_certinfo->certificate->GetSSLCertificateChain().Clone());
1448 ASSERT_EQ(initial_local_certinfo->fingerprints.size(), 2u);
1449 ASSERT_EQ(initial_remote_certinfo->fingerprints.size(), 2u);
1450
1451 rtc::scoped_refptr<const RTCStatsReport> first_report =
1452 stats_->GetStatsReport();
1453 const auto* first_local_cert0 = GetCertificateStatsFromFingerprint(
1454 first_report, initial_local_certinfo->fingerprints[0]);
1455 const auto* first_local_cert1 = GetCertificateStatsFromFingerprint(
1456 first_report, initial_local_certinfo->fingerprints[1]);
1457 const auto* first_remote_cert0 = GetCertificateStatsFromFingerprint(
1458 first_report, initial_remote_certinfo->fingerprints[0]);
1459 const auto* first_remote_cert1 = GetCertificateStatsFromFingerprint(
1460 first_report, initial_remote_certinfo->fingerprints[1]);
1461 ASSERT_TRUE(first_local_cert0);
1462 ASSERT_TRUE(first_local_cert1);
1463 ASSERT_TRUE(first_remote_cert0);
1464 ASSERT_TRUE(first_remote_cert1);
Philipp Hanckeb81823a2023-01-04 14:17:421465 EXPECT_EQ(first_local_cert0->timestamp().us(), rtc::TimeMicros());
1466 EXPECT_EQ(first_local_cert1->timestamp().us(), rtc::TimeMicros());
1467 EXPECT_EQ(first_remote_cert0->timestamp().us(), rtc::TimeMicros());
1468 EXPECT_EQ(first_remote_cert1->timestamp().us(), rtc::TimeMicros());
Henrik Boström69d23c92022-09-26 12:13:171469
1470 // Replace all certificates.
1471 std::unique_ptr<CertificateInfo> updated_local_certinfo =
1472 CreateFakeCertificateAndInfoFromDers(
1473 {"UpdatedLocalCertA", "UpdatedLocalCertB"});
1474 pc_->SetLocalCertificate(kTransportName, updated_local_certinfo->certificate);
1475 std::unique_ptr<CertificateInfo> updated_remote_certinfo =
1476 CreateFakeCertificateAndInfoFromDers(
1477 {"UpdatedRemoteCertA", "UpdatedRemoteCertB"});
1478 pc_->SetRemoteCertChain(
1479 kTransportName,
1480 updated_remote_certinfo->certificate->GetSSLCertificateChain().Clone());
1481 // This test assumes fingerprints are different for the old and new
1482 // certificates.
1483 EXPECT_NE(initial_local_certinfo->fingerprints,
1484 updated_local_certinfo->fingerprints);
1485 EXPECT_NE(initial_remote_certinfo->fingerprints,
1486 updated_remote_certinfo->fingerprints);
1487
1488 // Advance time to ensure a fresh stats report, but don't clear the
1489 // certificate stats cache.
1490 fake_clock.AdvanceTime(TimeDelta::Seconds(1));
1491 rtc::scoped_refptr<const RTCStatsReport> second_report =
1492 stats_->GetStatsReport();
1493 // We expect to see the same certificates as before due to not clearing the
1494 // certificate cache.
1495 const auto* second_local_cert0 =
1496 second_report->GetAs<RTCCertificateStats>(first_local_cert0->id());
1497 const auto* second_local_cert1 =
1498 second_report->GetAs<RTCCertificateStats>(first_local_cert1->id());
1499 const auto* second_remote_cert0 =
1500 second_report->GetAs<RTCCertificateStats>(first_remote_cert0->id());
1501 const auto* second_remote_cert1 =
1502 second_report->GetAs<RTCCertificateStats>(first_remote_cert1->id());
1503 ASSERT_TRUE(second_local_cert0);
1504 ASSERT_TRUE(second_local_cert1);
1505 ASSERT_TRUE(second_remote_cert0);
1506 ASSERT_TRUE(second_remote_cert1);
1507 // The information in the certificate stats are obsolete.
1508 EXPECT_EQ(*second_local_cert0->fingerprint,
1509 initial_local_certinfo->fingerprints[0]);
1510 EXPECT_EQ(*second_local_cert1->fingerprint,
1511 initial_local_certinfo->fingerprints[1]);
1512 EXPECT_EQ(*second_remote_cert0->fingerprint,
1513 initial_remote_certinfo->fingerprints[0]);
1514 EXPECT_EQ(*second_remote_cert1->fingerprint,
1515 initial_remote_certinfo->fingerprints[1]);
1516 // But timestamps are up-to-date, because this is a fresh stats report.
Philipp Hanckeb81823a2023-01-04 14:17:421517 EXPECT_EQ(second_local_cert0->timestamp().us(), rtc::TimeMicros());
1518 EXPECT_EQ(second_local_cert1->timestamp().us(), rtc::TimeMicros());
1519 EXPECT_EQ(second_remote_cert0->timestamp().us(), rtc::TimeMicros());
1520 EXPECT_EQ(second_remote_cert1->timestamp().us(), rtc::TimeMicros());
Henrik Boström69d23c92022-09-26 12:13:171521 // The updated certificates are not part of the report yet.
1522 EXPECT_FALSE(GetCertificateStatsFromFingerprint(
1523 second_report, updated_local_certinfo->fingerprints[0]));
1524 EXPECT_FALSE(GetCertificateStatsFromFingerprint(
1525 second_report, updated_local_certinfo->fingerprints[1]));
1526 EXPECT_FALSE(GetCertificateStatsFromFingerprint(
1527 second_report, updated_remote_certinfo->fingerprints[0]));
1528 EXPECT_FALSE(GetCertificateStatsFromFingerprint(
1529 second_report, updated_remote_certinfo->fingerprints[1]));
1530
1531 // Clear the cache, including the cached certificates.
1532 stats_->stats_collector()->ClearCachedStatsReport();
1533 rtc::scoped_refptr<const RTCStatsReport> third_report =
1534 stats_->GetStatsReport();
1535 // Now the old certificates stats should be deleted.
1536 EXPECT_FALSE(third_report->Get(first_local_cert0->id()));
1537 EXPECT_FALSE(third_report->Get(first_local_cert1->id()));
1538 EXPECT_FALSE(third_report->Get(first_remote_cert0->id()));
1539 EXPECT_FALSE(third_report->Get(first_remote_cert1->id()));
1540 // And updated certificates exist.
1541 EXPECT_TRUE(GetCertificateStatsFromFingerprint(
1542 third_report, updated_local_certinfo->fingerprints[0]));
1543 EXPECT_TRUE(GetCertificateStatsFromFingerprint(
1544 third_report, updated_local_certinfo->fingerprints[1]));
1545 EXPECT_TRUE(GetCertificateStatsFromFingerprint(
1546 third_report, updated_remote_certinfo->fingerprints[0]));
1547 EXPECT_TRUE(GetCertificateStatsFromFingerprint(
1548 third_report, updated_remote_certinfo->fingerprints[1]));
1549}
1550
Harald Alvestrand928e7a32019-07-31 11:16:451551TEST_F(RTCStatsCollectorTest, CollectTwoRTCDataChannelStatsWithPendingId) {
Philipp Hancke423faa62023-04-18 11:27:301552 // Note: The test assumes data channel IDs are predictable.
1553 // This is not a safe assumption, but in order to make it work for
1554 // the test, we reset the ID allocator at test start.
1555 SctpDataChannel::ResetInternalIdAllocatorForTesting(-1);
Niels Möllere7cc8832022-01-04 14:20:031556 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
Tommifaf33872023-03-16 08:25:291557 data_channel_controller_->weak_ptr(), /*id=*/-1,
1558 DataChannelInterface::kConnecting));
Niels Möllere7cc8832022-01-04 14:20:031559 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
Tommifaf33872023-03-16 08:25:291560 data_channel_controller_->weak_ptr(), /*id=*/-1,
1561 DataChannelInterface::kConnecting));
Harald Alvestrand928e7a32019-07-31 11:16:451562
1563 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Philipp Hancke423faa62023-04-18 11:27:301564 RTCDataChannelStats expected_data_channel0("D0", Timestamp::Zero());
1565 // Default values from MockDataChannel.
1566 expected_data_channel0.label = "MockSctpDataChannel";
1567 expected_data_channel0.protocol = "someProtocol";
1568 expected_data_channel0.state = "connecting";
1569 expected_data_channel0.messages_sent = 0;
1570 expected_data_channel0.bytes_sent = 0;
1571 expected_data_channel0.messages_received = 0;
1572 expected_data_channel0.bytes_received = 0;
1573
1574 ASSERT_TRUE(report->Get(expected_data_channel0.id()));
1575 EXPECT_EQ(
1576 expected_data_channel0,
1577 report->Get(expected_data_channel0.id())->cast_to<RTCDataChannelStats>());
Harald Alvestrand928e7a32019-07-31 11:16:451578}
1579
hboscc555c52016-10-18 19:48:311580TEST_F(RTCStatsCollectorTest, CollectRTCDataChannelStats) {
Harald Alvestrand928e7a32019-07-31 11:16:451581 // Note: The test assumes data channel IDs are predictable.
1582 // This is not a safe assumption, but in order to make it work for
1583 // the test, we reset the ID allocator at test start.
Taylor Brandstetter3a034e12020-07-09 22:32:341584 SctpDataChannel::ResetInternalIdAllocatorForTesting(-1);
Niels Möllere7cc8832022-01-04 14:20:031585 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
Tommifaf33872023-03-16 08:25:291586 data_channel_controller_->weak_ptr(), 0, "MockSctpDataChannel0",
Philipp Hancke423faa62023-04-18 11:27:301587 DataChannelInterface::kConnecting, "proto1", 1, 2, 3, 4));
Philipp Hanckeb81823a2023-01-04 14:17:421588 RTCDataChannelStats expected_data_channel0("D0", Timestamp::Zero());
Taylor Brandstetter3a034e12020-07-09 22:32:341589 expected_data_channel0.label = "MockSctpDataChannel0";
Philipp Hancke423faa62023-04-18 11:27:301590 expected_data_channel0.protocol = "proto1";
Harald Alvestrand10ef8472020-06-05 13:38:511591 expected_data_channel0.data_channel_identifier = 0;
hbosdbb64d82016-12-21 09:57:461592 expected_data_channel0.state = "connecting";
1593 expected_data_channel0.messages_sent = 1;
1594 expected_data_channel0.bytes_sent = 2;
1595 expected_data_channel0.messages_received = 3;
1596 expected_data_channel0.bytes_received = 4;
1597
Niels Möllere7cc8832022-01-04 14:20:031598 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
Tommifaf33872023-03-16 08:25:291599 data_channel_controller_->weak_ptr(), 1, "MockSctpDataChannel1",
Philipp Hancke423faa62023-04-18 11:27:301600 DataChannelInterface::kOpen, "proto2", 5, 6, 7, 8));
Philipp Hanckeb81823a2023-01-04 14:17:421601 RTCDataChannelStats expected_data_channel1("D1", Timestamp::Zero());
Taylor Brandstetter3a034e12020-07-09 22:32:341602 expected_data_channel1.label = "MockSctpDataChannel1";
Philipp Hancke423faa62023-04-18 11:27:301603 expected_data_channel1.protocol = "proto2";
Harald Alvestrand10ef8472020-06-05 13:38:511604 expected_data_channel1.data_channel_identifier = 1;
hbosdbb64d82016-12-21 09:57:461605 expected_data_channel1.state = "open";
1606 expected_data_channel1.messages_sent = 5;
1607 expected_data_channel1.bytes_sent = 6;
1608 expected_data_channel1.messages_received = 7;
1609 expected_data_channel1.bytes_received = 8;
1610
Niels Möllere7cc8832022-01-04 14:20:031611 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
Tommifaf33872023-03-16 08:25:291612 data_channel_controller_->weak_ptr(), 2, "MockSctpDataChannel2",
Philipp Hancke423faa62023-04-18 11:27:301613 DataChannelInterface::kClosing, "proto1", 9, 10, 11, 12));
Philipp Hanckeb81823a2023-01-04 14:17:421614 RTCDataChannelStats expected_data_channel2("D2", Timestamp::Zero());
Taylor Brandstetter3a034e12020-07-09 22:32:341615 expected_data_channel2.label = "MockSctpDataChannel2";
Philipp Hancke423faa62023-04-18 11:27:301616 expected_data_channel2.protocol = "proto1";
Harald Alvestrand10ef8472020-06-05 13:38:511617 expected_data_channel2.data_channel_identifier = 2;
hbosdbb64d82016-12-21 09:57:461618 expected_data_channel2.state = "closing";
1619 expected_data_channel2.messages_sent = 9;
1620 expected_data_channel2.bytes_sent = 10;
1621 expected_data_channel2.messages_received = 11;
1622 expected_data_channel2.bytes_received = 12;
1623
Niels Möllere7cc8832022-01-04 14:20:031624 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
Tommifaf33872023-03-16 08:25:291625 data_channel_controller_->weak_ptr(), 3, "MockSctpDataChannel3",
Philipp Hancke423faa62023-04-18 11:27:301626 DataChannelInterface::kClosed, "proto3", 13, 14, 15, 16));
Philipp Hanckeb81823a2023-01-04 14:17:421627 RTCDataChannelStats expected_data_channel3("D3", Timestamp::Zero());
Taylor Brandstetter3a034e12020-07-09 22:32:341628 expected_data_channel3.label = "MockSctpDataChannel3";
Philipp Hancke423faa62023-04-18 11:27:301629 expected_data_channel3.protocol = "proto3";
Harald Alvestrand10ef8472020-06-05 13:38:511630 expected_data_channel3.data_channel_identifier = 3;
hbosdbb64d82016-12-21 09:57:461631 expected_data_channel3.state = "closed";
1632 expected_data_channel3.messages_sent = 13;
1633 expected_data_channel3.bytes_sent = 14;
1634 expected_data_channel3.messages_received = 15;
1635 expected_data_channel3.bytes_received = 16;
hboscc555c52016-10-18 19:48:311636
Steve Anton5b387312018-02-03 00:00:201637 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1638
hbosdbb64d82016-12-21 09:57:461639 ASSERT_TRUE(report->Get(expected_data_channel0.id()));
Yves Gerey665174f2018-06-19 13:03:051640 EXPECT_EQ(
1641 expected_data_channel0,
1642 report->Get(expected_data_channel0.id())->cast_to<RTCDataChannelStats>());
hbosdbb64d82016-12-21 09:57:461643 ASSERT_TRUE(report->Get(expected_data_channel1.id()));
Yves Gerey665174f2018-06-19 13:03:051644 EXPECT_EQ(
1645 expected_data_channel1,
1646 report->Get(expected_data_channel1.id())->cast_to<RTCDataChannelStats>());
hbosdbb64d82016-12-21 09:57:461647 ASSERT_TRUE(report->Get(expected_data_channel2.id()));
Yves Gerey665174f2018-06-19 13:03:051648 EXPECT_EQ(
1649 expected_data_channel2,
1650 report->Get(expected_data_channel2.id())->cast_to<RTCDataChannelStats>());
hbosdbb64d82016-12-21 09:57:461651 ASSERT_TRUE(report->Get(expected_data_channel3.id()));
Yves Gerey665174f2018-06-19 13:03:051652 EXPECT_EQ(
1653 expected_data_channel3,
1654 report->Get(expected_data_channel3.id())->cast_to<RTCDataChannelStats>());
hboscc555c52016-10-18 19:48:311655}
1656
hbosab9f6e42016-10-07 09:18:471657TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidateStats) {
1658 // Candidates in the first transport stats.
Jonas Oreland0d13bbd2022-03-02 10:17:361659 std::unique_ptr<cricket::Candidate> a_local_host = CreateFakeCandidate(
1660 "1.2.3.4", 5, "a_local_host's protocol", rtc::ADAPTER_TYPE_VPN,
1661 cricket::LOCAL_PORT_TYPE, 0, rtc::ADAPTER_TYPE_ETHERNET);
Philipp Hanckeb81823a2023-01-04 14:17:421662 RTCLocalIceCandidateStats expected_a_local_host("I" + a_local_host->id(),
1663 Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291664 expected_a_local_host.transport_id = "Ta0";
Gary Liu37e489c2017-11-21 18:49:361665 expected_a_local_host.network_type = "vpn";
hbosc42ba322016-12-21 11:31:451666 expected_a_local_host.ip = "1.2.3.4";
Philipp Hanckea9ba4502021-03-22 12:22:541667 expected_a_local_host.address = "1.2.3.4";
hbosc42ba322016-12-21 11:31:451668 expected_a_local_host.port = 5;
1669 expected_a_local_host.protocol = "a_local_host's protocol";
1670 expected_a_local_host.candidate_type = "host";
1671 expected_a_local_host.priority = 0;
Jonas Oreland0d13bbd2022-03-02 10:17:361672 expected_a_local_host.vpn = true;
Henrik Boströmc929ab42023-06-15 13:17:451673 expected_a_local_host.network_adapter_type = "ethernet";
Philipp Hancke0e3cd632022-09-27 08:23:091674 expected_a_local_host.foundation = "foundationIsAString";
1675 expected_a_local_host.username_fragment = "iceusernamefragment";
hbosc42ba322016-12-21 11:31:451676
hbosab9f6e42016-10-07 09:18:471677 std::unique_ptr<cricket::Candidate> a_remote_srflx = CreateFakeCandidate(
Gary Liu37e489c2017-11-21 18:49:361678 "6.7.8.9", 10, "remote_srflx's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
1679 cricket::STUN_PORT_TYPE, 1);
Henrik Boström8dfc90f2022-09-02 07:39:291680 RTCRemoteIceCandidateStats expected_a_remote_srflx("I" + a_remote_srflx->id(),
Philipp Hanckeb81823a2023-01-04 14:17:421681 Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291682 expected_a_remote_srflx.transport_id = "Ta0";
hbosc42ba322016-12-21 11:31:451683 expected_a_remote_srflx.ip = "6.7.8.9";
Philipp Hanckea9ba4502021-03-22 12:22:541684 expected_a_remote_srflx.address = "6.7.8.9";
hbosc42ba322016-12-21 11:31:451685 expected_a_remote_srflx.port = 10;
1686 expected_a_remote_srflx.protocol = "remote_srflx's protocol";
1687 expected_a_remote_srflx.candidate_type = "srflx";
1688 expected_a_remote_srflx.priority = 1;
Philipp Hancke0e3cd632022-09-27 08:23:091689 expected_a_remote_srflx.foundation = "foundationIsAString";
1690 expected_a_remote_srflx.username_fragment = "iceusernamefragment";
hbosc42ba322016-12-21 11:31:451691
hbosab9f6e42016-10-07 09:18:471692 std::unique_ptr<cricket::Candidate> a_local_prflx = CreateFakeCandidate(
Jonas Oreland0d13bbd2022-03-02 10:17:361693 "11.12.13.14", 15, "a_local_prflx's protocol",
1694 rtc::ADAPTER_TYPE_CELLULAR_2G, cricket::PRFLX_PORT_TYPE, 2);
Henrik Boström8dfc90f2022-09-02 07:39:291695 RTCLocalIceCandidateStats expected_a_local_prflx("I" + a_local_prflx->id(),
Philipp Hanckeb81823a2023-01-04 14:17:421696 Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291697 expected_a_local_prflx.transport_id = "Ta0";
Gary Liu37e489c2017-11-21 18:49:361698 expected_a_local_prflx.network_type = "cellular";
hbosc42ba322016-12-21 11:31:451699 expected_a_local_prflx.ip = "11.12.13.14";
Philipp Hanckea9ba4502021-03-22 12:22:541700 expected_a_local_prflx.address = "11.12.13.14";
hbosc42ba322016-12-21 11:31:451701 expected_a_local_prflx.port = 15;
1702 expected_a_local_prflx.protocol = "a_local_prflx's protocol";
1703 expected_a_local_prflx.candidate_type = "prflx";
1704 expected_a_local_prflx.priority = 2;
Jonas Oreland0d13bbd2022-03-02 10:17:361705 expected_a_local_prflx.vpn = false;
Henrik Boströmc929ab42023-06-15 13:17:451706 expected_a_local_prflx.network_adapter_type = "cellular2g";
Philipp Hancke0e3cd632022-09-27 08:23:091707 expected_a_local_prflx.foundation = "foundationIsAString";
1708 expected_a_local_prflx.username_fragment = "iceusernamefragment";
hbosc42ba322016-12-21 11:31:451709
hbosab9f6e42016-10-07 09:18:471710 std::unique_ptr<cricket::Candidate> a_remote_relay = CreateFakeCandidate(
Gary Liu37e489c2017-11-21 18:49:361711 "16.17.18.19", 20, "a_remote_relay's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
1712 cricket::RELAY_PORT_TYPE, 3);
Henrik Boström8dfc90f2022-09-02 07:39:291713 RTCRemoteIceCandidateStats expected_a_remote_relay("I" + a_remote_relay->id(),
Philipp Hanckeb81823a2023-01-04 14:17:421714 Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291715 expected_a_remote_relay.transport_id = "Ta0";
hbosc42ba322016-12-21 11:31:451716 expected_a_remote_relay.ip = "16.17.18.19";
Philipp Hanckea9ba4502021-03-22 12:22:541717 expected_a_remote_relay.address = "16.17.18.19";
hbosc42ba322016-12-21 11:31:451718 expected_a_remote_relay.port = 20;
1719 expected_a_remote_relay.protocol = "a_remote_relay's protocol";
1720 expected_a_remote_relay.candidate_type = "relay";
1721 expected_a_remote_relay.priority = 3;
Philipp Hancke0e3cd632022-09-27 08:23:091722 expected_a_remote_relay.foundation = "foundationIsAString";
1723 expected_a_remote_relay.username_fragment = "iceusernamefragment";
hbosc42ba322016-12-21 11:31:451724
Philipp Hancke95513752018-09-27 12:40:081725 std::unique_ptr<cricket::Candidate> a_local_relay = CreateFakeCandidate(
1726 "16.17.18.19", 21, "a_local_relay's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
1727 cricket::RELAY_PORT_TYPE, 1);
1728 a_local_relay->set_relay_protocol("tcp");
Philipp Hancke05b29c72022-02-02 11:06:151729 a_local_relay->set_url("turn:url1");
Philipp Hancke95513752018-09-27 12:40:081730
Henrik Boström8dfc90f2022-09-02 07:39:291731 RTCLocalIceCandidateStats expected_a_local_relay("I" + a_local_relay->id(),
Philipp Hanckeb81823a2023-01-04 14:17:421732 Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291733 expected_a_local_relay.transport_id = "Ta0";
Philipp Hanckefbd52c02021-11-10 22:02:171734 expected_a_local_relay.network_type = "unknown";
Philipp Hancke95513752018-09-27 12:40:081735 expected_a_local_relay.ip = "16.17.18.19";
Philipp Hanckea9ba4502021-03-22 12:22:541736 expected_a_local_relay.address = "16.17.18.19";
Philipp Hancke95513752018-09-27 12:40:081737 expected_a_local_relay.port = 21;
1738 expected_a_local_relay.protocol = "a_local_relay's protocol";
1739 expected_a_local_relay.relay_protocol = "tcp";
1740 expected_a_local_relay.candidate_type = "relay";
1741 expected_a_local_relay.priority = 1;
Philipp Hancke05b29c72022-02-02 11:06:151742 expected_a_local_relay.url = "turn:url1";
Jonas Oreland0d13bbd2022-03-02 10:17:361743 expected_a_local_relay.vpn = false;
Henrik Boströmc929ab42023-06-15 13:17:451744 expected_a_local_relay.network_adapter_type = "unknown";
Philipp Hancke0e3cd632022-09-27 08:23:091745 expected_a_local_relay.foundation = "foundationIsAString";
1746 expected_a_local_relay.username_fragment = "iceusernamefragment";
Philipp Hancke95513752018-09-27 12:40:081747
Philipp Hancke21c4b1e2021-11-11 06:45:591748 std::unique_ptr<cricket::Candidate> a_local_relay_prflx = CreateFakeCandidate(
1749 "11.12.13.20", 22, "a_local_relay_prflx's protocol",
1750 rtc::ADAPTER_TYPE_UNKNOWN, cricket::PRFLX_PORT_TYPE, 1);
1751 a_local_relay_prflx->set_relay_protocol("udp");
1752
1753 RTCLocalIceCandidateStats expected_a_local_relay_prflx(
Philipp Hanckeb81823a2023-01-04 14:17:421754 "I" + a_local_relay_prflx->id(), Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291755 expected_a_local_relay_prflx.transport_id = "Ta0";
Philipp Hancke21c4b1e2021-11-11 06:45:591756 expected_a_local_relay_prflx.network_type = "unknown";
1757 expected_a_local_relay_prflx.ip = "11.12.13.20";
1758 expected_a_local_relay_prflx.address = "11.12.13.20";
1759 expected_a_local_relay_prflx.port = 22;
1760 expected_a_local_relay_prflx.protocol = "a_local_relay_prflx's protocol";
1761 expected_a_local_relay_prflx.relay_protocol = "udp";
1762 expected_a_local_relay_prflx.candidate_type = "prflx";
1763 expected_a_local_relay_prflx.priority = 1;
Jonas Oreland0d13bbd2022-03-02 10:17:361764 expected_a_local_relay_prflx.vpn = false;
Henrik Boströmc929ab42023-06-15 13:17:451765 expected_a_local_relay_prflx.network_adapter_type = "unknown";
Philipp Hancke0e3cd632022-09-27 08:23:091766 expected_a_local_relay_prflx.foundation = "foundationIsAString";
1767 expected_a_local_relay_prflx.username_fragment = "iceusernamefragment";
Philipp Hancke21c4b1e2021-11-11 06:45:591768
Philipp Hancke6e57ca22022-06-09 13:58:181769 // A non-paired local candidate.
1770 std::unique_ptr<cricket::Candidate> a_local_host_not_paired =
1771 CreateFakeCandidate("1.2.3.4", 4404, "a_local_host_not_paired's protocol",
1772 rtc::ADAPTER_TYPE_VPN, cricket::LOCAL_PORT_TYPE, 0,
1773 rtc::ADAPTER_TYPE_ETHERNET);
1774 RTCLocalIceCandidateStats expected_a_local_host_not_paired(
Philipp Hanckeb81823a2023-01-04 14:17:421775 "I" + a_local_host_not_paired->id(), Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291776 expected_a_local_host_not_paired.transport_id = "Ta0";
Philipp Hancke6e57ca22022-06-09 13:58:181777 expected_a_local_host_not_paired.network_type = "vpn";
1778 expected_a_local_host_not_paired.ip = "1.2.3.4";
1779 expected_a_local_host_not_paired.address = "1.2.3.4";
1780 expected_a_local_host_not_paired.port = 4404;
1781 expected_a_local_host_not_paired.protocol =
1782 "a_local_host_not_paired's protocol";
1783 expected_a_local_host_not_paired.candidate_type = "host";
1784 expected_a_local_host_not_paired.priority = 0;
1785 expected_a_local_host_not_paired.vpn = true;
Henrik Boströmc929ab42023-06-15 13:17:451786 expected_a_local_host_not_paired.network_adapter_type = "ethernet";
Philipp Hancke0e3cd632022-09-27 08:23:091787 expected_a_local_host_not_paired.foundation = "foundationIsAString";
1788 expected_a_local_host_not_paired.username_fragment = "iceusernamefragment";
Philipp Hancke6e57ca22022-06-09 13:58:181789
hbosab9f6e42016-10-07 09:18:471790 // Candidates in the second transport stats.
Gary Liu37e489c2017-11-21 18:49:361791 std::unique_ptr<cricket::Candidate> b_local =
1792 CreateFakeCandidate("42.42.42.42", 42, "b_local's protocol",
1793 rtc::ADAPTER_TYPE_WIFI, cricket::LOCAL_PORT_TYPE, 42);
Philipp Hanckeb81823a2023-01-04 14:17:421794 RTCLocalIceCandidateStats expected_b_local("I" + b_local->id(),
1795 Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291796 expected_b_local.transport_id = "Tb0";
Gary Liu37e489c2017-11-21 18:49:361797 expected_b_local.network_type = "wifi";
hbosc42ba322016-12-21 11:31:451798 expected_b_local.ip = "42.42.42.42";
Philipp Hanckea9ba4502021-03-22 12:22:541799 expected_b_local.address = "42.42.42.42";
hbosc42ba322016-12-21 11:31:451800 expected_b_local.port = 42;
1801 expected_b_local.protocol = "b_local's protocol";
1802 expected_b_local.candidate_type = "host";
1803 expected_b_local.priority = 42;
Jonas Oreland0d13bbd2022-03-02 10:17:361804 expected_b_local.vpn = false;
Henrik Boströmc929ab42023-06-15 13:17:451805 expected_b_local.network_adapter_type = "wifi";
Philipp Hancke0e3cd632022-09-27 08:23:091806 expected_b_local.foundation = "foundationIsAString";
1807 expected_b_local.username_fragment = "iceusernamefragment";
hbosc42ba322016-12-21 11:31:451808
hbosab9f6e42016-10-07 09:18:471809 std::unique_ptr<cricket::Candidate> b_remote = CreateFakeCandidate(
Gary Liu37e489c2017-11-21 18:49:361810 "42.42.42.42", 42, "b_remote's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
1811 cricket::LOCAL_PORT_TYPE, 42);
Philipp Hanckeb81823a2023-01-04 14:17:421812 RTCRemoteIceCandidateStats expected_b_remote("I" + b_remote->id(),
1813 Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291814 expected_b_remote.transport_id = "Tb0";
hbosc42ba322016-12-21 11:31:451815 expected_b_remote.ip = "42.42.42.42";
Philipp Hanckea9ba4502021-03-22 12:22:541816 expected_b_remote.address = "42.42.42.42";
hbosc42ba322016-12-21 11:31:451817 expected_b_remote.port = 42;
1818 expected_b_remote.protocol = "b_remote's protocol";
1819 expected_b_remote.candidate_type = "host";
1820 expected_b_remote.priority = 42;
Philipp Hancke0e3cd632022-09-27 08:23:091821 expected_b_remote.foundation = "foundationIsAString";
1822 expected_b_remote.username_fragment = "iceusernamefragment";
hbosab9f6e42016-10-07 09:18:471823
Philipp Hancke95513752018-09-27 12:40:081824 // Add candidate pairs to connection.
hbosab9f6e42016-10-07 09:18:471825 cricket::TransportChannelStats a_transport_channel_stats;
Jonas Oreland149dc722019-08-28 06:10:271826 a_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
hbosab9f6e42016-10-07 09:18:471827 cricket::ConnectionInfo());
Jonas Oreland149dc722019-08-28 06:10:271828 a_transport_channel_stats.ice_transport_stats.connection_infos[0]
1829 .local_candidate = *a_local_host.get();
1830 a_transport_channel_stats.ice_transport_stats.connection_infos[0]
1831 .remote_candidate = *a_remote_srflx.get();
1832 a_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
hbosab9f6e42016-10-07 09:18:471833 cricket::ConnectionInfo());
Jonas Oreland149dc722019-08-28 06:10:271834 a_transport_channel_stats.ice_transport_stats.connection_infos[1]
1835 .local_candidate = *a_local_prflx.get();
1836 a_transport_channel_stats.ice_transport_stats.connection_infos[1]
1837 .remote_candidate = *a_remote_relay.get();
1838 a_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
Philipp Hancke95513752018-09-27 12:40:081839 cricket::ConnectionInfo());
Jonas Oreland149dc722019-08-28 06:10:271840 a_transport_channel_stats.ice_transport_stats.connection_infos[2]
1841 .local_candidate = *a_local_relay.get();
1842 a_transport_channel_stats.ice_transport_stats.connection_infos[2]
1843 .remote_candidate = *a_remote_relay.get();
Philipp Hancke21c4b1e2021-11-11 06:45:591844 a_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
1845 cricket::ConnectionInfo());
1846 a_transport_channel_stats.ice_transport_stats.connection_infos[3]
1847 .local_candidate = *a_local_relay_prflx.get();
1848 a_transport_channel_stats.ice_transport_stats.connection_infos[3]
1849 .remote_candidate = *a_remote_relay.get();
Philipp Hancke6e57ca22022-06-09 13:58:181850 a_transport_channel_stats.ice_transport_stats.candidate_stats_list.push_back(
1851 cricket::CandidateStats(*a_local_host_not_paired.get()));
Steve Anton5b387312018-02-03 00:00:201852
1853 pc_->AddVoiceChannel("audio", "a");
1854 pc_->SetTransportStats("a", a_transport_channel_stats);
hbosab9f6e42016-10-07 09:18:471855
1856 cricket::TransportChannelStats b_transport_channel_stats;
Jonas Oreland149dc722019-08-28 06:10:271857 b_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
hbosab9f6e42016-10-07 09:18:471858 cricket::ConnectionInfo());
Jonas Oreland149dc722019-08-28 06:10:271859 b_transport_channel_stats.ice_transport_stats.connection_infos[0]
1860 .local_candidate = *b_local.get();
1861 b_transport_channel_stats.ice_transport_stats.connection_infos[0]
1862 .remote_candidate = *b_remote.get();
hbosab9f6e42016-10-07 09:18:471863
Steve Anton5b387312018-02-03 00:00:201864 pc_->AddVideoChannel("video", "b");
1865 pc_->SetTransportStats("b", b_transport_channel_stats);
hbosab9f6e42016-10-07 09:18:471866
Steve Anton5b387312018-02-03 00:00:201867 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbosc42ba322016-12-21 11:31:451868
hbosb4e426e2017-01-02 17:59:311869 ASSERT_TRUE(report->Get(expected_a_local_host.id()));
Yves Gerey665174f2018-06-19 13:03:051870 EXPECT_EQ(expected_a_local_host, report->Get(expected_a_local_host.id())
1871 ->cast_to<RTCLocalIceCandidateStats>());
Philipp Hancke6e57ca22022-06-09 13:58:181872
1873 ASSERT_TRUE(report->Get(expected_a_local_host_not_paired.id()));
1874 EXPECT_EQ(expected_a_local_host_not_paired,
1875 report->Get(expected_a_local_host_not_paired.id())
1876 ->cast_to<RTCLocalIceCandidateStats>());
1877
hbosb4e426e2017-01-02 17:59:311878 ASSERT_TRUE(report->Get(expected_a_remote_srflx.id()));
hbosc42ba322016-12-21 11:31:451879 EXPECT_EQ(expected_a_remote_srflx,
Yves Gerey665174f2018-06-19 13:03:051880 report->Get(expected_a_remote_srflx.id())
1881 ->cast_to<RTCRemoteIceCandidateStats>());
hbosb4e426e2017-01-02 17:59:311882 ASSERT_TRUE(report->Get(expected_a_local_prflx.id()));
Yves Gerey665174f2018-06-19 13:03:051883 EXPECT_EQ(expected_a_local_prflx, report->Get(expected_a_local_prflx.id())
1884 ->cast_to<RTCLocalIceCandidateStats>());
hbosb4e426e2017-01-02 17:59:311885 ASSERT_TRUE(report->Get(expected_a_remote_relay.id()));
hbosc42ba322016-12-21 11:31:451886 EXPECT_EQ(expected_a_remote_relay,
Yves Gerey665174f2018-06-19 13:03:051887 report->Get(expected_a_remote_relay.id())
1888 ->cast_to<RTCRemoteIceCandidateStats>());
Philipp Hanckefbd52c02021-11-10 22:02:171889 ASSERT_TRUE(report->Get(expected_a_local_relay.id()));
1890 EXPECT_EQ(expected_a_local_relay, report->Get(expected_a_local_relay.id())
1891 ->cast_to<RTCLocalIceCandidateStats>());
Philipp Hancke21c4b1e2021-11-11 06:45:591892 ASSERT_TRUE(report->Get(expected_a_local_relay_prflx.id()));
1893 EXPECT_EQ(expected_a_local_relay_prflx,
1894 report->Get(expected_a_local_relay_prflx.id())
1895 ->cast_to<RTCLocalIceCandidateStats>());
hbosb4e426e2017-01-02 17:59:311896 ASSERT_TRUE(report->Get(expected_b_local.id()));
Yves Gerey665174f2018-06-19 13:03:051897 EXPECT_EQ(
1898 expected_b_local,
1899 report->Get(expected_b_local.id())->cast_to<RTCLocalIceCandidateStats>());
hbosb4e426e2017-01-02 17:59:311900 ASSERT_TRUE(report->Get(expected_b_remote.id()));
Yves Gerey665174f2018-06-19 13:03:051901 EXPECT_EQ(expected_b_remote, report->Get(expected_b_remote.id())
1902 ->cast_to<RTCRemoteIceCandidateStats>());
Henrik Boström8dfc90f2022-09-02 07:39:291903 EXPECT_TRUE(report->Get("Ta0"));
1904 EXPECT_TRUE(report->Get("Tb0"));
hbosab9f6e42016-10-07 09:18:471905}
1906
hbosc47a0c32016-10-11 21:54:491907TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidatePairStats) {
Steve Anton5b387312018-02-03 00:00:201908 const char kTransportName[] = "transport";
hbos338f78a2017-02-07 14:41:211909
Gary Liu37e489c2017-11-21 18:49:361910 std::unique_ptr<cricket::Candidate> local_candidate =
1911 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
1912 cricket::LOCAL_PORT_TYPE, 42);
Philipp Hancke0e3cd632022-09-27 08:23:091913 local_candidate->set_username("local_iceusernamefragment");
1914
hbosc47a0c32016-10-11 21:54:491915 std::unique_ptr<cricket::Candidate> remote_candidate = CreateFakeCandidate(
Gary Liu37e489c2017-11-21 18:49:361916 "42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_UNKNOWN,
Philipp Hancke0e3cd632022-09-27 08:23:091917 cricket::STUN_PORT_TYPE, 42);
1918 remote_candidate->set_related_address(rtc::SocketAddress("192.168.2.1", 43));
1919 remote_candidate->set_username("remote_iceusernamefragment");
hbosc47a0c32016-10-11 21:54:491920
hbosc47a0c32016-10-11 21:54:491921 cricket::ConnectionInfo connection_info;
hbos338f78a2017-02-07 14:41:211922 connection_info.best_connection = false;
hbosc47a0c32016-10-11 21:54:491923 connection_info.local_candidate = *local_candidate.get();
1924 connection_info.remote_candidate = *remote_candidate.get();
1925 connection_info.writable = true;
Taylor Brandstetter79326ea2021-09-28 22:09:531926 connection_info.sent_discarded_packets = 3;
1927 connection_info.sent_total_packets = 10;
1928 connection_info.packets_received = 51;
1929 connection_info.sent_discarded_bytes = 7;
hbosc47a0c32016-10-11 21:54:491930 connection_info.sent_total_bytes = 42;
1931 connection_info.recv_total_bytes = 1234;
hbosbf8d3e52017-02-28 14:34:471932 connection_info.total_round_trip_time_ms = 0;
Danil Chapovalov66cadcc2018-06-19 14:47:431933 connection_info.current_round_trip_time_ms = absl::nullopt;
hbosd82f5122016-12-09 12:12:391934 connection_info.recv_ping_requests = 2020;
Henrik Boström839439a2022-09-06 09:16:361935 connection_info.sent_ping_requests_total = 2222;
hbose448dd52016-12-12 09:22:531936 connection_info.sent_ping_requests_before_first_response = 2000;
hbosc47a0c32016-10-11 21:54:491937 connection_info.recv_ping_responses = 4321;
1938 connection_info.sent_ping_responses = 1000;
hbos06495bc2017-01-02 16:08:181939 connection_info.state = cricket::IceCandidatePairState::IN_PROGRESS;
1940 connection_info.priority = 5555;
hbos92eaec62017-02-27 09:38:081941 connection_info.nominated = false;
Philipp Hancke0487c572022-11-01 16:03:011942 connection_info.last_data_received = Timestamp::Millis(2500);
1943 connection_info.last_data_sent = Timestamp::Millis(5200);
hbosc47a0c32016-10-11 21:54:491944
1945 cricket::TransportChannelStats transport_channel_stats;
hbos0583b282016-11-30 09:50:141946 transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
Jonas Oreland149dc722019-08-28 06:10:271947 transport_channel_stats.ice_transport_stats.connection_infos.push_back(
1948 connection_info);
hbosc47a0c32016-10-11 21:54:491949
Steve Anton5b387312018-02-03 00:00:201950 pc_->AddVideoChannel("video", kTransportName);
1951 pc_->SetTransportStats(kTransportName, transport_channel_stats);
hbosc47a0c32016-10-11 21:54:491952
Steve Anton5b387312018-02-03 00:00:201953 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos0583b282016-11-30 09:50:141954
Henrik Boström8dfc90f2022-09-02 07:39:291955 RTCIceCandidatePairStats expected_pair(
1956 "CP" + local_candidate->id() + "_" + remote_candidate->id(),
Philipp Hanckeb81823a2023-01-04 14:17:421957 report->timestamp());
hbos0583b282016-11-30 09:50:141958 expected_pair.transport_id =
Henrik Boström8dfc90f2022-09-02 07:39:291959 "Ttransport" + rtc::ToString(cricket::ICE_CANDIDATE_COMPONENT_RTP);
1960 expected_pair.local_candidate_id = "I" + local_candidate->id();
1961 expected_pair.remote_candidate_id = "I" + remote_candidate->id();
Henrik Boströmc929ab42023-06-15 13:17:451962 expected_pair.state = "in-progress";
hbos06495bc2017-01-02 16:08:181963 expected_pair.priority = 5555;
hbos92eaec62017-02-27 09:38:081964 expected_pair.nominated = false;
hbos0583b282016-11-30 09:50:141965 expected_pair.writable = true;
Taylor Brandstetter79326ea2021-09-28 22:09:531966 expected_pair.packets_sent = 7;
1967 expected_pair.packets_received = 51;
1968 expected_pair.packets_discarded_on_send = 3;
hbos0583b282016-11-30 09:50:141969 expected_pair.bytes_sent = 42;
1970 expected_pair.bytes_received = 1234;
Taylor Brandstetter79326ea2021-09-28 22:09:531971 expected_pair.bytes_discarded_on_send = 7;
hbosbf8d3e52017-02-28 14:34:471972 expected_pair.total_round_trip_time = 0.0;
hbosd82f5122016-12-09 12:12:391973 expected_pair.requests_received = 2020;
Henrik Boström839439a2022-09-06 09:16:361974 expected_pair.requests_sent = 2222;
hbos0583b282016-11-30 09:50:141975 expected_pair.responses_received = 4321;
1976 expected_pair.responses_sent = 1000;
Henrik Boström839439a2022-09-06 09:16:361977 expected_pair.consent_requests_sent = (2222 - 2000);
Philipp Hancke0487c572022-11-01 16:03:011978 expected_pair.last_packet_received_timestamp = 2500;
1979 expected_pair.last_packet_sent_timestamp = 5200;
1980
Artem Titovcfea2182021-08-09 23:22:311981 // `expected_pair.current_round_trip_time` should be undefined because the
hbosbf8d3e52017-02-28 14:34:471982 // current RTT is not set.
Artem Titovcfea2182021-08-09 23:22:311983 // `expected_pair.available_[outgoing/incoming]_bitrate` should be undefined
hbos338f78a2017-02-07 14:41:211984 // because is is not the current pair.
hbos0583b282016-11-30 09:50:141985
hbosdbb64d82016-12-21 09:57:461986 ASSERT_TRUE(report->Get(expected_pair.id()));
hbos0583b282016-11-30 09:50:141987 EXPECT_EQ(
1988 expected_pair,
1989 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
hbosb4e426e2017-01-02 17:59:311990 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
hbos0583b282016-11-30 09:50:141991
hbos92eaec62017-02-27 09:38:081992 // Set nominated and "GetStats" again.
Jonas Oreland149dc722019-08-28 06:10:271993 transport_channel_stats.ice_transport_stats.connection_infos[0].nominated =
1994 true;
Steve Anton5b387312018-02-03 00:00:201995 pc_->SetTransportStats(kTransportName, transport_channel_stats);
1996 report = stats_->GetFreshStatsReport();
hbos92eaec62017-02-27 09:38:081997 expected_pair.nominated = true;
1998 ASSERT_TRUE(report->Get(expected_pair.id()));
1999 EXPECT_EQ(
2000 expected_pair,
2001 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
2002 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
2003
hbosbf8d3e52017-02-28 14:34:472004 // Set round trip times and "GetStats" again.
Jonas Oreland149dc722019-08-28 06:10:272005 transport_channel_stats.ice_transport_stats.connection_infos[0]
2006 .total_round_trip_time_ms = 7331;
2007 transport_channel_stats.ice_transport_stats.connection_infos[0]
2008 .current_round_trip_time_ms = 1337;
Steve Anton5b387312018-02-03 00:00:202009 pc_->SetTransportStats(kTransportName, transport_channel_stats);
2010 report = stats_->GetFreshStatsReport();
hbosbf8d3e52017-02-28 14:34:472011 expected_pair.total_round_trip_time = 7.331;
2012 expected_pair.current_round_trip_time = 1.337;
2013 ASSERT_TRUE(report->Get(expected_pair.id()));
2014 EXPECT_EQ(
2015 expected_pair,
2016 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
2017 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
2018
hbos338f78a2017-02-07 14:41:212019 // Make pair the current pair, clear bandwidth and "GetStats" again.
Jonas Oreland149dc722019-08-28 06:10:272020 transport_channel_stats.ice_transport_stats.connection_infos[0]
2021 .best_connection = true;
Steve Anton5b387312018-02-03 00:00:202022 pc_->SetTransportStats(kTransportName, transport_channel_stats);
2023 report = stats_->GetFreshStatsReport();
hbos338f78a2017-02-07 14:41:212024 // |expected_pair.available_[outgoing/incoming]_bitrate| should still be
2025 // undefined because bandwidth is not set.
2026 ASSERT_TRUE(report->Get(expected_pair.id()));
2027 EXPECT_EQ(
2028 expected_pair,
2029 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
2030 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
2031
2032 // Set bandwidth and "GetStats" again.
Harald Alvestranda6544372023-11-13 09:33:562033 Call::Stats call_stats;
stefanf79ade12017-06-02 13:44:032034 const int kSendBandwidth = 888;
2035 call_stats.send_bandwidth_bps = kSendBandwidth;
2036 const int kRecvBandwidth = 999;
2037 call_stats.recv_bandwidth_bps = kRecvBandwidth;
Steve Anton5b387312018-02-03 00:00:202038 pc_->SetCallStats(call_stats);
2039 report = stats_->GetFreshStatsReport();
stefanf79ade12017-06-02 13:44:032040 expected_pair.available_outgoing_bitrate = kSendBandwidth;
2041 expected_pair.available_incoming_bitrate = kRecvBandwidth;
hbos338f78a2017-02-07 14:41:212042 ASSERT_TRUE(report->Get(expected_pair.id()));
2043 EXPECT_EQ(
2044 expected_pair,
2045 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
2046 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
2047
hbosc42ba322016-12-21 11:31:452048 RTCLocalIceCandidateStats expected_local_candidate(
Philipp Hanckeb81823a2023-01-04 14:17:422049 *expected_pair.local_candidate_id, report->timestamp());
hbosb4e426e2017-01-02 17:59:312050 expected_local_candidate.transport_id = *expected_pair.transport_id;
Gary Liu37e489c2017-11-21 18:49:362051 expected_local_candidate.network_type = "wifi";
hbosc42ba322016-12-21 11:31:452052 expected_local_candidate.ip = "42.42.42.42";
Philipp Hanckea9ba4502021-03-22 12:22:542053 expected_local_candidate.address = "42.42.42.42";
hbosc42ba322016-12-21 11:31:452054 expected_local_candidate.port = 42;
2055 expected_local_candidate.protocol = "protocol";
2056 expected_local_candidate.candidate_type = "host";
2057 expected_local_candidate.priority = 42;
Philipp Hancke0e3cd632022-09-27 08:23:092058 expected_local_candidate.foundation = "foundationIsAString";
2059 expected_local_candidate.username_fragment = "local_iceusernamefragment";
Jonas Oreland0d13bbd2022-03-02 10:17:362060 expected_local_candidate.vpn = false;
Henrik Boströmc929ab42023-06-15 13:17:452061 expected_local_candidate.network_adapter_type = "wifi";
hbosc42ba322016-12-21 11:31:452062 ASSERT_TRUE(report->Get(expected_local_candidate.id()));
2063 EXPECT_EQ(expected_local_candidate,
Yves Gerey665174f2018-06-19 13:03:052064 report->Get(expected_local_candidate.id())
2065 ->cast_to<RTCLocalIceCandidateStats>());
hbosc42ba322016-12-21 11:31:452066
2067 RTCRemoteIceCandidateStats expected_remote_candidate(
Philipp Hanckeb81823a2023-01-04 14:17:422068 *expected_pair.remote_candidate_id, report->timestamp());
hbosb4e426e2017-01-02 17:59:312069 expected_remote_candidate.transport_id = *expected_pair.transport_id;
hbosc42ba322016-12-21 11:31:452070 expected_remote_candidate.ip = "42.42.42.42";
Philipp Hanckea9ba4502021-03-22 12:22:542071 expected_remote_candidate.address = "42.42.42.42";
hbosc42ba322016-12-21 11:31:452072 expected_remote_candidate.port = 42;
2073 expected_remote_candidate.protocol = "protocol";
Philipp Hancke0e3cd632022-09-27 08:23:092074 expected_remote_candidate.candidate_type = "srflx";
hbosc42ba322016-12-21 11:31:452075 expected_remote_candidate.priority = 42;
Philipp Hancke0e3cd632022-09-27 08:23:092076 expected_remote_candidate.foundation = "foundationIsAString";
2077 expected_remote_candidate.username_fragment = "remote_iceusernamefragment";
2078 expected_remote_candidate.related_address = "192.168.2.1";
2079 expected_remote_candidate.related_port = 43;
hbosc42ba322016-12-21 11:31:452080 ASSERT_TRUE(report->Get(expected_remote_candidate.id()));
2081 EXPECT_EQ(expected_remote_candidate,
Yves Gerey665174f2018-06-19 13:03:052082 report->Get(expected_remote_candidate.id())
2083 ->cast_to<RTCRemoteIceCandidateStats>());
hbosc47a0c32016-10-11 21:54:492084}
2085
hbosd565b732016-08-30 21:04:352086TEST_F(RTCStatsCollectorTest, CollectRTCPeerConnectionStats) {
hbosd565b732016-08-30 21:04:352087 {
Steve Anton5b387312018-02-03 00:00:202088 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Philipp Hanckeb81823a2023-01-04 14:17:422089 RTCPeerConnectionStats expected("P", report->timestamp());
hbos82ebe022016-11-14 09:41:092090 expected.data_channels_opened = 0;
2091 expected.data_channels_closed = 0;
Henrik Boström8dfc90f2022-09-02 07:39:292092 ASSERT_TRUE(report->Get("P"));
2093 EXPECT_EQ(expected, report->Get("P")->cast_to<RTCPeerConnectionStats>());
hbosd565b732016-08-30 21:04:352094 }
2095
Tommi55f72802023-03-27 10:39:332096 FakeDataChannelController controller(pc_->network_thread());
Taylor Brandstetter3a034e12020-07-09 22:32:342097 rtc::scoped_refptr<SctpDataChannel> dummy_channel_a = SctpDataChannel::Create(
Tommie9aa8672023-03-20 13:43:092098 controller.weak_ptr(), "DummyChannelA", false, InternalDataChannelInit(),
Tomas Gunnarsson7d3cfbf2020-06-15 11:47:422099 rtc::Thread::Current(), rtc::Thread::Current());
Taylor Brandstetter3a034e12020-07-09 22:32:342100 rtc::scoped_refptr<SctpDataChannel> dummy_channel_b = SctpDataChannel::Create(
Tommie9aa8672023-03-20 13:43:092101 controller.weak_ptr(), "DummyChannelB", false, InternalDataChannelInit(),
Tomas Gunnarsson7d3cfbf2020-06-15 11:47:422102 rtc::Thread::Current(), rtc::Thread::Current());
hbosd565b732016-08-30 21:04:352103
Tommid2afbaf2023-03-02 09:51:162104 stats_->stats_collector()->OnSctpDataChannelStateChanged(
Tommi56548982023-03-27 16:07:342105 dummy_channel_a->internal_id(), DataChannelInterface::DataState::kOpen);
hbos82ebe022016-11-14 09:41:092106 // Closing a channel that is not opened should not affect the counts.
Tommid2afbaf2023-03-02 09:51:162107 stats_->stats_collector()->OnSctpDataChannelStateChanged(
Tommi56548982023-03-27 16:07:342108 dummy_channel_b->internal_id(), DataChannelInterface::DataState::kClosed);
hbos82ebe022016-11-14 09:41:092109
hbosd565b732016-08-30 21:04:352110 {
Steve Anton5b387312018-02-03 00:00:202111 rtc::scoped_refptr<const RTCStatsReport> report =
2112 stats_->GetFreshStatsReport();
Philipp Hanckeb81823a2023-01-04 14:17:422113 RTCPeerConnectionStats expected("P", report->timestamp());
hbos82ebe022016-11-14 09:41:092114 expected.data_channels_opened = 1;
2115 expected.data_channels_closed = 0;
Henrik Boström8dfc90f2022-09-02 07:39:292116 ASSERT_TRUE(report->Get("P"));
2117 EXPECT_EQ(expected, report->Get("P")->cast_to<RTCPeerConnectionStats>());
hbos82ebe022016-11-14 09:41:092118 }
2119
Tommid2afbaf2023-03-02 09:51:162120 stats_->stats_collector()->OnSctpDataChannelStateChanged(
Tommi56548982023-03-27 16:07:342121 dummy_channel_b->internal_id(), DataChannelInterface::DataState::kOpen);
Tommid2afbaf2023-03-02 09:51:162122 stats_->stats_collector()->OnSctpDataChannelStateChanged(
Tommi56548982023-03-27 16:07:342123 dummy_channel_b->internal_id(), DataChannelInterface::DataState::kClosed);
hbos82ebe022016-11-14 09:41:092124
2125 {
Steve Anton5b387312018-02-03 00:00:202126 rtc::scoped_refptr<const RTCStatsReport> report =
2127 stats_->GetFreshStatsReport();
Philipp Hanckeb81823a2023-01-04 14:17:422128 RTCPeerConnectionStats expected("P", report->timestamp());
hbos82ebe022016-11-14 09:41:092129 expected.data_channels_opened = 2;
2130 expected.data_channels_closed = 1;
Henrik Boström8dfc90f2022-09-02 07:39:292131 ASSERT_TRUE(report->Get("P"));
2132 EXPECT_EQ(expected, report->Get("P")->cast_to<RTCPeerConnectionStats>());
hbosd565b732016-08-30 21:04:352133 }
hbos5bf9def2017-03-20 10:14:142134
2135 // Re-opening a data channel (or opening a new data channel that is re-using
2136 // the same address in memory) should increase the opened count.
Tommid2afbaf2023-03-02 09:51:162137 stats_->stats_collector()->OnSctpDataChannelStateChanged(
Tommi56548982023-03-27 16:07:342138 dummy_channel_b->internal_id(), DataChannelInterface::DataState::kOpen);
hbos5bf9def2017-03-20 10:14:142139
2140 {
Steve Anton5b387312018-02-03 00:00:202141 rtc::scoped_refptr<const RTCStatsReport> report =
2142 stats_->GetFreshStatsReport();
Philipp Hanckeb81823a2023-01-04 14:17:422143 RTCPeerConnectionStats expected("P", report->timestamp());
hbos5bf9def2017-03-20 10:14:142144 expected.data_channels_opened = 3;
2145 expected.data_channels_closed = 1;
Henrik Boström8dfc90f2022-09-02 07:39:292146 ASSERT_TRUE(report->Get("P"));
2147 EXPECT_EQ(expected, report->Get("P")->cast_to<RTCPeerConnectionStats>());
hbos5bf9def2017-03-20 10:14:142148 }
2149
Tommid2afbaf2023-03-02 09:51:162150 stats_->stats_collector()->OnSctpDataChannelStateChanged(
Tommi56548982023-03-27 16:07:342151 dummy_channel_a->internal_id(), DataChannelInterface::DataState::kClosed);
Tommid2afbaf2023-03-02 09:51:162152 stats_->stats_collector()->OnSctpDataChannelStateChanged(
Tommi56548982023-03-27 16:07:342153 dummy_channel_b->internal_id(), DataChannelInterface::DataState::kClosed);
hbos5bf9def2017-03-20 10:14:142154
2155 {
Steve Anton5b387312018-02-03 00:00:202156 rtc::scoped_refptr<const RTCStatsReport> report =
2157 stats_->GetFreshStatsReport();
Philipp Hanckeb81823a2023-01-04 14:17:422158 RTCPeerConnectionStats expected("P", report->timestamp());
hbos5bf9def2017-03-20 10:14:142159 expected.data_channels_opened = 3;
2160 expected.data_channels_closed = 3;
Henrik Boström8dfc90f2022-09-02 07:39:292161 ASSERT_TRUE(report->Get("P"));
2162 EXPECT_EQ(expected, report->Get("P")->cast_to<RTCPeerConnectionStats>());
hbos5bf9def2017-03-20 10:14:142163 }
hbosd565b732016-08-30 21:04:352164}
2165
Philipp Hancke1f98b462023-03-07 08:53:592166TEST_F(RTCStatsCollectorTest, CollectRTCInboundRtpStreamStats_Audio) {
hboseeafe942016-11-01 10:00:172167 cricket::VoiceMediaInfo voice_media_info;
hbos0adb8282016-11-23 10:32:062168
hboseeafe942016-11-01 10:00:172169 voice_media_info.receivers.push_back(cricket::VoiceReceiverInfo());
2170 voice_media_info.receivers[0].local_stats.push_back(
2171 cricket::SsrcReceiverInfo());
2172 voice_media_info.receivers[0].local_stats[0].ssrc = 1;
Harald Alvestrand719487e2017-12-13 11:26:042173 voice_media_info.receivers[0].packets_lost = -1; // Signed per RFC3550
Minyue Li28a2c632021-07-07 13:53:382174 voice_media_info.receivers[0].packets_discarded = 7788;
Philipp Hancke6a7bf102023-04-21 17:32:422175 voice_media_info.receivers[0].packets_received = 2;
Jakob Ivarssone54914a2021-07-01 09:16:052176 voice_media_info.receivers[0].nacks_sent = 5;
Ivo Creusen8d8ffdb2019-04-30 07:45:212177 voice_media_info.receivers[0].fec_packets_discarded = 5566;
2178 voice_media_info.receivers[0].fec_packets_received = 6677;
Philipp Hancke6a7bf102023-04-21 17:32:422179 voice_media_info.receivers[0].payload_bytes_received = 3;
2180 voice_media_info.receivers[0].header_and_padding_bytes_received = 4;
Oskar Sundbomcbc71b22017-11-16 09:56:072181 voice_media_info.receivers[0].codec_payload_type = 42;
hboseeafe942016-11-01 10:00:172182 voice_media_info.receivers[0].jitter_ms = 4500;
Eldar Rello4e5bc9f2020-07-06 11:18:072183 voice_media_info.receivers[0].jitter_buffer_delay_seconds = 1.0;
Ivo Creusen11fdb082022-07-04 12:16:392184 voice_media_info.receivers[0].jitter_buffer_target_delay_seconds = 1.1;
Ivo Creusen1a84b562022-07-19 14:33:102185 voice_media_info.receivers[0].jitter_buffer_minimum_delay_seconds = 0.999;
Eldar Rello4e5bc9f2020-07-06 11:18:072186 voice_media_info.receivers[0].jitter_buffer_emitted_count = 2;
2187 voice_media_info.receivers[0].total_samples_received = 3;
2188 voice_media_info.receivers[0].concealed_samples = 4;
2189 voice_media_info.receivers[0].silent_concealed_samples = 5;
2190 voice_media_info.receivers[0].concealment_events = 6;
2191 voice_media_info.receivers[0].inserted_samples_for_deceleration = 7;
2192 voice_media_info.receivers[0].removed_samples_for_acceleration = 8;
Philipp Hanckeaa83cc72020-10-27 08:50:362193 voice_media_info.receivers[0].audio_level = 14442; // [0,32767]
Eldar Rello4e5bc9f2020-07-06 11:18:072194 voice_media_info.receivers[0].total_output_energy = 10.0;
2195 voice_media_info.receivers[0].total_output_duration = 11.0;
Henrik Boström2fb83072022-10-06 11:37:112196 voice_media_info.receivers[0].jitter_buffer_flushes = 7;
2197 voice_media_info.receivers[0].delayed_packet_outage_samples = 15;
2198 voice_media_info.receivers[0].relative_packet_arrival_delay_seconds = 16;
2199 voice_media_info.receivers[0].interruption_count = 7788;
2200 voice_media_info.receivers[0].total_interruption_duration_ms = 778899;
Danil Chapovalov54e95bc2023-06-02 12:54:452201 voice_media_info.receivers[0].last_packet_received = absl::nullopt;
hbos0adb8282016-11-23 10:32:062202
2203 RtpCodecParameters codec_parameters;
2204 codec_parameters.payload_type = 42;
deadbeefe702b302017-02-04 20:09:012205 codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
2206 codec_parameters.name = "dummy";
Oskar Sundbomcbc71b22017-11-16 09:56:072207 codec_parameters.clock_rate = 0;
hbos0adb8282016-11-23 10:32:062208 voice_media_info.receive_codecs.insert(
2209 std::make_pair(codec_parameters.payload_type, codec_parameters));
2210
Harald Alvestrand2f553702023-03-07 10:10:032211 auto voice_media_channels =
Tommi19015512022-02-02 10:49:352212 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Henrik Boström5b3541f2018-03-19 12:52:562213 stats_->SetupRemoteTrackAndReceiver(
2214 cricket::MEDIA_TYPE_AUDIO, "RemoteAudioTrackID", "RemoteStreamId", 1);
hboseeafe942016-11-01 10:00:172215
Fredrik Hernqvist828de802023-01-19 14:04:542216 // Needed for playoutId to be populated.
2217 pc_->SetAudioDeviceStats(AudioDeviceModule::Stats());
2218 pc_->GetTransceiversInternal()[0]->internal()->set_current_direction(
2219 RtpTransceiverDirection::kSendRecv);
2220
Steve Anton5b387312018-02-03 00:00:202221 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hboseeafe942016-11-01 10:00:172222
Philipp Hancke1f98b462023-03-07 08:53:592223 RTCInboundRtpStreamStats expected_audio("ITTransportName1A1",
Philipp Hanckeb81823a2023-01-04 14:17:422224 report->timestamp());
hbos3443bb72017-02-07 14:28:112225 expected_audio.ssrc = 1;
Philipp Hancke3bc01662018-08-28 12:55:032226 expected_audio.kind = "audio";
Henrik Boströma6c7d5c2022-06-16 14:55:312227 expected_audio.track_identifier = "RemoteAudioTrackID";
Henrik Boström1ab61882022-06-16 15:07:332228 expected_audio.mid = "AudioMid";
Henrik Boström8dfc90f2022-09-02 07:39:292229 expected_audio.transport_id = "TTransportName1";
2230 expected_audio.codec_id = "CITTransportName1_42";
hboseeafe942016-11-01 10:00:172231 expected_audio.packets_received = 2;
Jakob Ivarssone54914a2021-07-01 09:16:052232 expected_audio.nack_count = 5;
Ivo Creusen8d8ffdb2019-04-30 07:45:212233 expected_audio.fec_packets_discarded = 5566;
2234 expected_audio.fec_packets_received = 6677;
hboseeafe942016-11-01 10:00:172235 expected_audio.bytes_received = 3;
Niels Möllerac0a4cb2019-10-09 13:01:332236 expected_audio.header_bytes_received = 4;
Harald Alvestrand719487e2017-12-13 11:26:042237 expected_audio.packets_lost = -1;
Minyue Li28a2c632021-07-07 13:53:382238 expected_audio.packets_discarded = 7788;
Artem Titovcfea2182021-08-09 23:22:312239 // `expected_audio.last_packet_received_timestamp` should be undefined.
hboseeafe942016-11-01 10:00:172240 expected_audio.jitter = 4.5;
Eldar Rello4e5bc9f2020-07-06 11:18:072241 expected_audio.jitter_buffer_delay = 1.0;
Ivo Creusen11fdb082022-07-04 12:16:392242 expected_audio.jitter_buffer_target_delay = 1.1;
Ivo Creusen1a84b562022-07-19 14:33:102243 expected_audio.jitter_buffer_minimum_delay = 0.999;
Eldar Rello4e5bc9f2020-07-06 11:18:072244 expected_audio.jitter_buffer_emitted_count = 2;
2245 expected_audio.total_samples_received = 3;
2246 expected_audio.concealed_samples = 4;
2247 expected_audio.silent_concealed_samples = 5;
2248 expected_audio.concealment_events = 6;
2249 expected_audio.inserted_samples_for_deceleration = 7;
2250 expected_audio.removed_samples_for_acceleration = 8;
Philipp Hanckeaa83cc72020-10-27 08:50:362251 expected_audio.audio_level = 14442.0 / 32767.0; // [0,1]
Eldar Rello4e5bc9f2020-07-06 11:18:072252 expected_audio.total_audio_energy = 10.0;
2253 expected_audio.total_samples_duration = 11.0;
Henrik Boström2fb83072022-10-06 11:37:112254 expected_audio.jitter_buffer_flushes = 7;
2255 expected_audio.delayed_packet_outage_samples = 15;
2256 expected_audio.relative_packet_arrival_delay = 16;
2257 expected_audio.interruption_count = 7788;
2258 expected_audio.total_interruption_duration = 778.899;
Fredrik Hernqvist828de802023-01-19 14:04:542259 expected_audio.playout_id = "AP";
Eldar Rello4e5bc9f2020-07-06 11:18:072260
nissec8ee8822017-01-18 15:20:552261 ASSERT_TRUE(report->Get(expected_audio.id()));
hbosa51d4f32017-02-16 13:34:482262 EXPECT_EQ(
Philipp Hancke1f98b462023-03-07 08:53:592263 report->Get(expected_audio.id())->cast_to<RTCInboundRtpStreamStats>(),
hbosa51d4f32017-02-16 13:34:482264 expected_audio);
Henrik Boström01738c62019-04-15 15:32:002265
2266 // Set previously undefined values and "GetStats" again.
Danil Chapovalov54e95bc2023-06-02 12:54:452267 voice_media_info.receivers[0].last_packet_received = Timestamp::Seconds(3);
Alessio Bazzicac366d512021-03-22 14:36:532268 expected_audio.last_packet_received_timestamp = 3000.0;
Åsa Perssonfcf79cc2019-10-22 13:23:442269 voice_media_info.receivers[0].estimated_playout_ntp_timestamp_ms = 4567;
2270 expected_audio.estimated_playout_timestamp = 4567;
Harald Alvestrand2f553702023-03-07 10:10:032271 voice_media_channels.first->SetStats(voice_media_info);
2272 voice_media_channels.second->SetStats(voice_media_info);
Henrik Boström01738c62019-04-15 15:32:002273
2274 report = stats_->GetFreshStatsReport();
2275
2276 ASSERT_TRUE(report->Get(expected_audio.id()));
2277 EXPECT_EQ(
Philipp Hancke1f98b462023-03-07 08:53:592278 report->Get(expected_audio.id())->cast_to<RTCInboundRtpStreamStats>(),
Henrik Boström01738c62019-04-15 15:32:002279 expected_audio);
hbos84abeb12017-01-16 14:16:442280 EXPECT_TRUE(report->Get(*expected_audio.transport_id));
2281 EXPECT_TRUE(report->Get(*expected_audio.codec_id));
hboseeafe942016-11-01 10:00:172282}
2283
Philipp Hancke1f98b462023-03-07 08:53:592284TEST_F(RTCStatsCollectorTest, CollectRTCInboundRtpStreamStats_Audio_PlayoutId) {
Fredrik Hernqvist828de802023-01-19 14:04:542285 cricket::VoiceMediaInfo voice_media_info;
2286
2287 voice_media_info.receivers.push_back(cricket::VoiceReceiverInfo());
2288 voice_media_info.receivers[0].local_stats.push_back(
2289 cricket::SsrcReceiverInfo());
2290 voice_media_info.receivers[0].local_stats[0].ssrc = 1;
2291
2292 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
2293 stats_->SetupRemoteTrackAndReceiver(
2294 cricket::MEDIA_TYPE_AUDIO, "RemoteAudioTrackID", "RemoteStreamId", 1);
2295 // Needed for playoutId to be populated.
2296 pc_->SetAudioDeviceStats(AudioDeviceModule::Stats());
2297
2298 {
2299 // We do not expect a playout id when only sending.
2300 pc_->GetTransceiversInternal()[0]->internal()->set_current_direction(
2301 RtpTransceiverDirection::kSendOnly);
2302 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
2303 ASSERT_TRUE(report->Get("ITTransportName1A1"));
2304 auto stats =
Philipp Hancke1f98b462023-03-07 08:53:592305 report->Get("ITTransportName1A1")->cast_to<RTCInboundRtpStreamStats>();
Fredrik Hernqvist828de802023-01-19 14:04:542306 ASSERT_FALSE(stats.playout_id.is_defined());
2307 }
2308 {
2309 // We do expect a playout id when receiving.
2310 pc_->GetTransceiversInternal()[0]->internal()->set_current_direction(
2311 RtpTransceiverDirection::kRecvOnly);
2312 rtc::scoped_refptr<const RTCStatsReport> report =
2313 stats_->GetFreshStatsReport();
2314 ASSERT_TRUE(report->Get("ITTransportName1A1"));
2315 auto stats =
Philipp Hancke1f98b462023-03-07 08:53:592316 report->Get("ITTransportName1A1")->cast_to<RTCInboundRtpStreamStats>();
Fredrik Hernqvist828de802023-01-19 14:04:542317 ASSERT_TRUE(stats.playout_id.is_defined());
2318 EXPECT_EQ(*stats.playout_id, "AP");
2319 }
2320}
2321
Philipp Hancke1f98b462023-03-07 08:53:592322TEST_F(RTCStatsCollectorTest, CollectRTCInboundRtpStreamStats_Video) {
hboseeafe942016-11-01 10:00:172323 cricket::VideoMediaInfo video_media_info;
hbos0adb8282016-11-23 10:32:062324
hboseeafe942016-11-01 10:00:172325 video_media_info.receivers.push_back(cricket::VideoReceiverInfo());
2326 video_media_info.receivers[0].local_stats.push_back(
2327 cricket::SsrcReceiverInfo());
2328 video_media_info.receivers[0].local_stats[0].ssrc = 1;
Philipp Hancke6a7bf102023-04-21 17:32:422329 video_media_info.receivers[0].packets_received = 2;
hbos02cd4d62016-12-09 12:19:442330 video_media_info.receivers[0].packets_lost = 42;
Philipp Hancke6a7bf102023-04-21 17:32:422331 video_media_info.receivers[0].payload_bytes_received = 3;
2332 video_media_info.receivers[0].header_and_padding_bytes_received = 12;
Oskar Sundbomcbc71b22017-11-16 09:56:072333 video_media_info.receivers[0].codec_payload_type = 42;
hbos820f5782016-11-22 11:16:502334 video_media_info.receivers[0].firs_sent = 5;
2335 video_media_info.receivers[0].plis_sent = 6;
2336 video_media_info.receivers[0].nacks_sent = 7;
Eldar Rello4e5bc9f2020-07-06 11:18:072337 video_media_info.receivers[0].frames_received = 8;
2338 video_media_info.receivers[0].frames_decoded = 9;
Rasmus Brandt2efae772019-06-27 12:29:342339 video_media_info.receivers[0].key_frames_decoded = 3;
Eldar Rello4e5bc9f2020-07-06 11:18:072340 video_media_info.receivers[0].frames_dropped = 13;
Danil Chapovalov66cadcc2018-06-19 14:47:432341 video_media_info.receivers[0].qp_sum = absl::nullopt;
Harald Alvestranda6544372023-11-13 09:33:562342 video_media_info.receivers[0].total_decode_time = TimeDelta::Seconds(9);
2343 video_media_info.receivers[0].total_processing_delay = TimeDelta::Millis(600);
2344 video_media_info.receivers[0].total_assembly_time = TimeDelta::Millis(500);
Philipp Hancke0359ba22022-05-05 13:55:362345 video_media_info.receivers[0].frames_assembled_from_multiple_packets = 23;
Johannes Kron00376e12019-11-25 09:25:422346 video_media_info.receivers[0].total_inter_frame_delay = 0.123;
2347 video_media_info.receivers[0].total_squared_inter_frame_delay = 0.00456;
Henrik Boströmc57a28c2022-10-06 09:59:052348 video_media_info.receivers[0].pause_count = 2;
2349 video_media_info.receivers[0].total_pauses_duration_ms = 10000;
2350 video_media_info.receivers[0].freeze_count = 3;
2351 video_media_info.receivers[0].total_freezes_duration_ms = 1000;
Di Wu (RP Room Eng)8af6b492021-02-20 01:34:222352 video_media_info.receivers[0].jitter_ms = 1199;
Byoungchan Lee899b29e2021-06-29 13:09:182353 video_media_info.receivers[0].jitter_buffer_delay_seconds = 3.456;
Ivo Creusen11fdb082022-07-04 12:16:392354 video_media_info.receivers[0].jitter_buffer_target_delay_seconds = 1.1;
Ivo Creusen1a84b562022-07-19 14:33:102355 video_media_info.receivers[0].jitter_buffer_minimum_delay_seconds = 0.999;
Byoungchan Lee899b29e2021-06-29 13:09:182356 video_media_info.receivers[0].jitter_buffer_emitted_count = 13;
Danil Chapovalov54e95bc2023-06-02 12:54:452357 video_media_info.receivers[0].last_packet_received = absl::nullopt;
Henrik Boström2e069262019-04-09 11:59:312358 video_media_info.receivers[0].content_type = VideoContentType::UNSPECIFIED;
Åsa Perssonfcf79cc2019-10-22 13:23:442359 video_media_info.receivers[0].estimated_playout_ntp_timestamp_ms =
2360 absl::nullopt;
Philipp Hancke656817c2023-06-22 09:41:352361 video_media_info.receivers[0].decoder_implementation_name = absl::nullopt;
Philipp Hancke6fb8d1a2022-05-30 10:37:042362 video_media_info.receivers[0].min_playout_delay_ms = 50;
Evan Shrubsole13c0be42022-10-31 11:03:102363 video_media_info.receivers[0].power_efficient_decoder = false;
Philipp Hanckef78d1f22023-04-25 08:23:472364 video_media_info.receivers[0].retransmitted_packets_received = 17;
2365 video_media_info.receivers[0].retransmitted_bytes_received = 62;
Philipp Hancke17e8a5c2023-06-21 11:53:412366 video_media_info.receivers[0].fec_packets_received = 32;
2367 video_media_info.receivers[0].fec_bytes_received = 54;
Philipp Hancke9b82b2f2023-07-28 10:27:132368 video_media_info.receivers[0].ssrc_groups.push_back(
2369 {cricket::kFidSsrcGroupSemantics, {1, 4404}});
Philipp Hanckee2e04512023-08-04 09:12:462370 video_media_info.receivers[0].ssrc_groups.push_back(
2371 {cricket::kFecFrSsrcGroupSemantics, {1, 5505}});
hbos0adb8282016-11-23 10:32:062372
Philipp Hancke3719a0c2022-07-04 16:24:462373 // Note: these two values intentionally differ,
2374 // only the decoded one should show up.
Philipp Hancke6a7bf102023-04-21 17:32:422375 video_media_info.receivers[0].framerate_received = 15;
Philipp Hancke3719a0c2022-07-04 16:24:462376 video_media_info.receivers[0].framerate_decoded = 5;
2377
hbos0adb8282016-11-23 10:32:062378 RtpCodecParameters codec_parameters;
2379 codec_parameters.payload_type = 42;
Philipp Hancke3719a0c2022-07-04 16:24:462380 codec_parameters.kind = cricket::MEDIA_TYPE_VIDEO;
deadbeefe702b302017-02-04 20:09:012381 codec_parameters.name = "dummy";
Oskar Sundbomcbc71b22017-11-16 09:56:072382 codec_parameters.clock_rate = 0;
hbos0adb8282016-11-23 10:32:062383 video_media_info.receive_codecs.insert(
2384 std::make_pair(codec_parameters.payload_type, codec_parameters));
2385
Harald Alvestrand2f553702023-03-07 10:10:032386 auto video_media_channels =
Tommi19015512022-02-02 10:49:352387 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström5b3541f2018-03-19 12:52:562388 stats_->SetupRemoteTrackAndReceiver(
2389 cricket::MEDIA_TYPE_VIDEO, "RemoteVideoTrackID", "RemoteStreamId", 1);
hboseeafe942016-11-01 10:00:172390
Steve Anton5b387312018-02-03 00:00:202391 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hboseeafe942016-11-01 10:00:172392
Philipp Hancke1f98b462023-03-07 08:53:592393 RTCInboundRtpStreamStats expected_video("ITTransportName1V1",
Philipp Hanckeb81823a2023-01-04 14:17:422394 report->timestamp());
hbos3443bb72017-02-07 14:28:112395 expected_video.ssrc = 1;
Philipp Hancke3bc01662018-08-28 12:55:032396 expected_video.kind = "video";
Henrik Boströma6c7d5c2022-06-16 14:55:312397 expected_video.track_identifier = "RemoteVideoTrackID";
Henrik Boström1ab61882022-06-16 15:07:332398 expected_video.mid = "VideoMid";
Henrik Boström8dfc90f2022-09-02 07:39:292399 expected_video.transport_id = "TTransportName1";
2400 expected_video.codec_id = "CITTransportName1_42";
hbos820f5782016-11-22 11:16:502401 expected_video.fir_count = 5;
2402 expected_video.pli_count = 6;
2403 expected_video.nack_count = 7;
2404 expected_video.packets_received = 2;
2405 expected_video.bytes_received = 3;
Niels Möllerac0a4cb2019-10-09 13:01:332406 expected_video.header_bytes_received = 12;
hbos02cd4d62016-12-09 12:19:442407 expected_video.packets_lost = 42;
Eldar Rello4e5bc9f2020-07-06 11:18:072408 expected_video.frames_received = 8;
2409 expected_video.frames_decoded = 9;
Rasmus Brandt2efae772019-06-27 12:29:342410 expected_video.key_frames_decoded = 3;
Eldar Rello4e5bc9f2020-07-06 11:18:072411 expected_video.frames_dropped = 13;
Artem Titovcfea2182021-08-09 23:22:312412 // `expected_video.qp_sum` should be undefined.
Johannes Kronbfd343b2019-07-01 08:07:502413 expected_video.total_decode_time = 9.0;
Philipp Hanckea16a6a62022-04-25 10:21:302414 expected_video.total_processing_delay = 0.6;
Philipp Hancke0359ba22022-05-05 13:55:362415 expected_video.total_assembly_time = 0.5;
2416 expected_video.frames_assembled_from_multiple_packets = 23;
Johannes Kron00376e12019-11-25 09:25:422417 expected_video.total_inter_frame_delay = 0.123;
2418 expected_video.total_squared_inter_frame_delay = 0.00456;
Henrik Boströmc57a28c2022-10-06 09:59:052419 expected_video.pause_count = 2;
2420 expected_video.total_pauses_duration = 10;
2421 expected_video.freeze_count = 3;
2422 expected_video.total_freezes_duration = 1;
Di Wu (RP Room Eng)8af6b492021-02-20 01:34:222423 expected_video.jitter = 1.199;
Byoungchan Lee899b29e2021-06-29 13:09:182424 expected_video.jitter_buffer_delay = 3.456;
Ivo Creusen11fdb082022-07-04 12:16:392425 expected_video.jitter_buffer_target_delay = 1.1;
Ivo Creusen1a84b562022-07-19 14:33:102426 expected_video.jitter_buffer_minimum_delay = 0.999;
Byoungchan Lee899b29e2021-06-29 13:09:182427 expected_video.jitter_buffer_emitted_count = 13;
Artem Titovcfea2182021-08-09 23:22:312428 // `expected_video.last_packet_received_timestamp` should be undefined.
2429 // `expected_video.content_type` should be undefined.
2430 // `expected_video.decoder_implementation` should be undefined.
Philipp Hancke6fb8d1a2022-05-30 10:37:042431 expected_video.min_playout_delay = 0.05;
Philipp Hancke3719a0c2022-07-04 16:24:462432 expected_video.frames_per_second = 5;
Evan Shrubsole13c0be42022-10-31 11:03:102433 expected_video.power_efficient_decoder = false;
Philipp Hanckef78d1f22023-04-25 08:23:472434 expected_video.retransmitted_packets_received = 17;
2435 expected_video.retransmitted_bytes_received = 62;
Philipp Hancke17e8a5c2023-06-21 11:53:412436 expected_video.fec_packets_received = 32;
2437 expected_video.fec_bytes_received = 54;
Philipp Hancke9b82b2f2023-07-28 10:27:132438 expected_video.rtx_ssrc = 4404;
Philipp Hanckee2e04512023-08-04 09:12:462439 expected_video.fec_ssrc = 5505;
hboseeafe942016-11-01 10:00:172440
nissec8ee8822017-01-18 15:20:552441 ASSERT_TRUE(report->Get(expected_video.id()));
hbosa51d4f32017-02-16 13:34:482442 EXPECT_EQ(
Philipp Hancke1f98b462023-03-07 08:53:592443 report->Get(expected_video.id())->cast_to<RTCInboundRtpStreamStats>(),
hbosa51d4f32017-02-16 13:34:482444 expected_video);
hboseeafe942016-11-01 10:00:172445
hbosa51d4f32017-02-16 13:34:482446 // Set previously undefined values and "GetStats" again.
Oskar Sundbomcbc71b22017-11-16 09:56:072447 video_media_info.receivers[0].qp_sum = 9;
hbosa51d4f32017-02-16 13:34:482448 expected_video.qp_sum = 9;
Danil Chapovalov54e95bc2023-06-02 12:54:452449 video_media_info.receivers[0].last_packet_received = Timestamp::Seconds(1);
Alessio Bazzica5cf8c2c2021-03-24 07:51:262450 expected_video.last_packet_received_timestamp = 1000.0;
Henrik Boström2e069262019-04-09 11:59:312451 video_media_info.receivers[0].content_type = VideoContentType::SCREENSHARE;
2452 expected_video.content_type = "screenshare";
Åsa Perssonfcf79cc2019-10-22 13:23:442453 video_media_info.receivers[0].estimated_playout_ntp_timestamp_ms = 1234;
2454 expected_video.estimated_playout_timestamp = 1234;
Henrik Boström6b430862019-08-16 11:09:512455 video_media_info.receivers[0].decoder_implementation_name = "libfoodecoder";
2456 expected_video.decoder_implementation = "libfoodecoder";
Evan Shrubsole13c0be42022-10-31 11:03:102457 video_media_info.receivers[0].power_efficient_decoder = true;
2458 expected_video.power_efficient_decoder = true;
Harald Alvestrand2f553702023-03-07 10:10:032459 video_media_channels.first->SetStats(video_media_info);
2460 video_media_channels.second->SetStats(video_media_info);
hbosa51d4f32017-02-16 13:34:482461
Steve Anton5b387312018-02-03 00:00:202462 report = stats_->GetFreshStatsReport();
hbosa51d4f32017-02-16 13:34:482463
2464 ASSERT_TRUE(report->Get(expected_video.id()));
2465 EXPECT_EQ(
Philipp Hancke1f98b462023-03-07 08:53:592466 report->Get(expected_video.id())->cast_to<RTCInboundRtpStreamStats>(),
hbosa51d4f32017-02-16 13:34:482467 expected_video);
hbos84abeb12017-01-16 14:16:442468 EXPECT_TRUE(report->Get(*expected_video.transport_id));
hbosa51d4f32017-02-16 13:34:482469 EXPECT_TRUE(report->Get(*expected_video.codec_id));
hboseeafe942016-11-01 10:00:172470}
2471
Fredrik Hernqvistefbe7532023-01-13 15:42:362472TEST_F(RTCStatsCollectorTest, CollectRTCAudioPlayoutStats) {
2473 AudioDeviceModule::Stats audio_device_stats;
2474 audio_device_stats.synthesized_samples_duration_s = 1;
2475 audio_device_stats.synthesized_samples_events = 2;
2476 audio_device_stats.total_samples_count = 3;
2477 audio_device_stats.total_samples_duration_s = 4;
2478 audio_device_stats.total_playout_delay_s = 5;
2479 pc_->SetAudioDeviceStats(audio_device_stats);
2480
2481 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
2482 auto stats_of_track_type = report->GetStatsOfType<RTCAudioPlayoutStats>();
2483 ASSERT_EQ(1U, stats_of_track_type.size());
2484
2485 RTCAudioPlayoutStats expected_stats("AP", report->timestamp());
Fredrik Hernqvist5adc2b62023-01-25 12:49:162486 expected_stats.kind = "audio";
Fredrik Hernqvistefbe7532023-01-13 15:42:362487 expected_stats.synthesized_samples_duration = 1;
2488 expected_stats.synthesized_samples_events = 2;
2489 expected_stats.total_samples_count = 3;
2490 expected_stats.total_samples_duration = 4;
2491 expected_stats.total_playout_delay = 5;
2492
2493 ASSERT_TRUE(report->Get(expected_stats.id()));
2494 EXPECT_EQ(report->Get(expected_stats.id())->cast_to<RTCAudioPlayoutStats>(),
2495 expected_stats);
2496}
2497
Henrik Boströmc5f8f802022-10-19 15:50:092498TEST_F(RTCStatsCollectorTest, CollectGoogTimingFrameInfo) {
2499 cricket::VideoMediaInfo video_media_info;
2500
2501 video_media_info.receivers.push_back(cricket::VideoReceiverInfo());
2502 video_media_info.receivers[0].local_stats.push_back(
2503 cricket::SsrcReceiverInfo());
2504 video_media_info.receivers[0].local_stats[0].ssrc = 1;
2505 TimingFrameInfo timing_frame_info;
2506 timing_frame_info.rtp_timestamp = 1;
2507 timing_frame_info.capture_time_ms = 2;
2508 timing_frame_info.encode_start_ms = 3;
2509 timing_frame_info.encode_finish_ms = 4;
2510 timing_frame_info.packetization_finish_ms = 5;
2511 timing_frame_info.pacer_exit_ms = 6;
2512 timing_frame_info.network_timestamp_ms = 7;
2513 timing_frame_info.network2_timestamp_ms = 8;
2514 timing_frame_info.receive_start_ms = 9;
2515 timing_frame_info.receive_finish_ms = 10;
2516 timing_frame_info.decode_start_ms = 11;
2517 timing_frame_info.decode_finish_ms = 12;
2518 timing_frame_info.render_time_ms = 13;
2519 timing_frame_info.flags = 14;
2520 video_media_info.receivers[0].timing_frame_info = timing_frame_info;
2521
2522 pc_->AddVideoChannel("Mid0", "Transport0", video_media_info);
2523 stats_->SetupRemoteTrackAndReceiver(
2524 cricket::MEDIA_TYPE_VIDEO, "RemoteVideoTrackID", "RemoteStreamId", 1);
2525
2526 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Philipp Hancke1f98b462023-03-07 08:53:592527 auto inbound_rtps = report->GetStatsOfType<RTCInboundRtpStreamStats>();
Henrik Boströmc5f8f802022-10-19 15:50:092528 ASSERT_EQ(inbound_rtps.size(), 1u);
2529 ASSERT_TRUE(inbound_rtps[0]->goog_timing_frame_info.is_defined());
2530 EXPECT_EQ(*inbound_rtps[0]->goog_timing_frame_info,
2531 "1,2,3,4,5,6,7,8,9,10,11,12,13,1,0");
2532}
2533
Philipp Hancke1f98b462023-03-07 08:53:592534TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRtpStreamStats_Audio) {
hbos6ded1902016-11-01 08:50:462535 cricket::VoiceMediaInfo voice_media_info;
hbos0adb8282016-11-23 10:32:062536
hbos6ded1902016-11-01 08:50:462537 voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
2538 voice_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
2539 voice_media_info.senders[0].local_stats[0].ssrc = 1;
2540 voice_media_info.senders[0].packets_sent = 2;
Henrik Boströmaebba7b2022-10-26 14:53:032541 voice_media_info.senders[0].total_packet_send_delay = TimeDelta::Seconds(1);
Henrik Boströmcf96e0f2019-04-17 11:51:532542 voice_media_info.senders[0].retransmitted_packets_sent = 20;
Niels Möllerac0a4cb2019-10-09 13:01:332543 voice_media_info.senders[0].payload_bytes_sent = 3;
2544 voice_media_info.senders[0].header_and_padding_bytes_sent = 12;
Henrik Boströmcf96e0f2019-04-17 11:51:532545 voice_media_info.senders[0].retransmitted_bytes_sent = 30;
Philipp Hancke6a7bf102023-04-21 17:32:422546 voice_media_info.senders[0].nacks_received = 31;
Jakob Ivarssonbf087452021-11-11 12:43:492547 voice_media_info.senders[0].target_bitrate = 32000;
Oskar Sundbomcbc71b22017-11-16 09:56:072548 voice_media_info.senders[0].codec_payload_type = 42;
Philipp Hancke684e2412022-07-28 10:41:002549 voice_media_info.senders[0].active = true;
hbos0adb8282016-11-23 10:32:062550
2551 RtpCodecParameters codec_parameters;
2552 codec_parameters.payload_type = 42;
deadbeefe702b302017-02-04 20:09:012553 codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
2554 codec_parameters.name = "dummy";
Oskar Sundbomcbc71b22017-11-16 09:56:072555 codec_parameters.clock_rate = 0;
hbos0adb8282016-11-23 10:32:062556 voice_media_info.send_codecs.insert(
2557 std::make_pair(codec_parameters.payload_type, codec_parameters));
2558
Tommi19015512022-02-02 10:49:352559 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Steve Anton5b387312018-02-03 00:00:202560 stats_->SetupLocalTrackAndSender(cricket::MEDIA_TYPE_AUDIO,
Henrik Boström646fda02019-05-22 13:49:422561 "LocalAudioTrackID", 1, true,
2562 /*attachment_id=*/50);
hbos6ded1902016-11-01 08:50:462563
Steve Anton5b387312018-02-03 00:00:202564 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos6ded1902016-11-01 08:50:462565
Philipp Hancke1f98b462023-03-07 08:53:592566 RTCOutboundRtpStreamStats expected_audio("OTTransportName1A1",
Philipp Hanckeb81823a2023-01-04 14:17:422567 report->timestamp());
Henrik Boström8dfc90f2022-09-02 07:39:292568 expected_audio.media_source_id = "SA50";
Artem Titovcfea2182021-08-09 23:22:312569 // `expected_audio.remote_id` should be undefined.
Henrik Boström1ab61882022-06-16 15:07:332570 expected_audio.mid = "AudioMid";
hbos3443bb72017-02-07 14:28:112571 expected_audio.ssrc = 1;
Philipp Hancke3bc01662018-08-28 12:55:032572 expected_audio.kind = "audio";
Henrik Boström8dfc90f2022-09-02 07:39:292573 expected_audio.transport_id = "TTransportName1";
2574 expected_audio.codec_id = "COTTransportName1_42";
hbos6ded1902016-11-01 08:50:462575 expected_audio.packets_sent = 2;
Henrik Boströmaebba7b2022-10-26 14:53:032576 expected_audio.total_packet_send_delay = 1;
Henrik Boströmcf96e0f2019-04-17 11:51:532577 expected_audio.retransmitted_packets_sent = 20;
hbos6ded1902016-11-01 08:50:462578 expected_audio.bytes_sent = 3;
Niels Möllerac0a4cb2019-10-09 13:01:332579 expected_audio.header_bytes_sent = 12;
Henrik Boströmcf96e0f2019-04-17 11:51:532580 expected_audio.retransmitted_bytes_sent = 30;
Jakob Ivarssone91c9922021-07-06 07:55:432581 expected_audio.nack_count = 31;
Jakob Ivarssonbf087452021-11-11 12:43:492582 expected_audio.target_bitrate = 32000;
Philipp Hancke684e2412022-07-28 10:41:002583 expected_audio.active = true;
hboscd195be2017-02-07 16:31:272584
hboscd195be2017-02-07 16:31:272585 ASSERT_TRUE(report->Get(expected_audio.id()));
hbosa51d4f32017-02-16 13:34:482586 EXPECT_EQ(
Philipp Hancke1f98b462023-03-07 08:53:592587 report->Get(expected_audio.id())->cast_to<RTCOutboundRtpStreamStats>(),
hbosa51d4f32017-02-16 13:34:482588 expected_audio);
skvladed02c6d2017-02-07 18:45:312589
hbosa51d4f32017-02-16 13:34:482590 ASSERT_TRUE(report->Get(expected_audio.id()));
2591 EXPECT_EQ(
Philipp Hancke1f98b462023-03-07 08:53:592592 report->Get(expected_audio.id())->cast_to<RTCOutboundRtpStreamStats>(),
hbosa51d4f32017-02-16 13:34:482593 expected_audio);
hbos84abeb12017-01-16 14:16:442594 EXPECT_TRUE(report->Get(*expected_audio.transport_id));
2595 EXPECT_TRUE(report->Get(*expected_audio.codec_id));
hbos6ded1902016-11-01 08:50:462596}
2597
Philipp Hancke1f98b462023-03-07 08:53:592598TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRtpStreamStats_Video) {
hbos6ded1902016-11-01 08:50:462599 cricket::VideoMediaInfo video_media_info;
hbos0adb8282016-11-23 10:32:062600
hbos6ded1902016-11-01 08:50:462601 video_media_info.senders.push_back(cricket::VideoSenderInfo());
2602 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
2603 video_media_info.senders[0].local_stats[0].ssrc = 1;
Philipp Hancke6a7bf102023-04-21 17:32:422604 video_media_info.senders[0].firs_received = 2;
2605 video_media_info.senders[0].plis_received = 3;
2606 video_media_info.senders[0].nacks_received = 4;
hbos6ded1902016-11-01 08:50:462607 video_media_info.senders[0].packets_sent = 5;
Henrik Boströmcf96e0f2019-04-17 11:51:532608 video_media_info.senders[0].retransmitted_packets_sent = 50;
Niels Möllerac0a4cb2019-10-09 13:01:332609 video_media_info.senders[0].payload_bytes_sent = 6;
2610 video_media_info.senders[0].header_and_padding_bytes_sent = 12;
Henrik Boströmcf96e0f2019-04-17 11:51:532611 video_media_info.senders[0].retransmitted_bytes_sent = 60;
Oskar Sundbomcbc71b22017-11-16 09:56:072612 video_media_info.senders[0].codec_payload_type = 42;
hbos6769c492017-01-02 16:35:132613 video_media_info.senders[0].frames_encoded = 8;
Rasmus Brandt2efae772019-06-27 12:29:342614 video_media_info.senders[0].key_frames_encoded = 3;
Henrik Boströmf71362f2019-04-08 14:14:232615 video_media_info.senders[0].total_encode_time_ms = 9000;
Henrik Boström23aff9b2019-05-20 13:15:382616 video_media_info.senders[0].total_encoded_bytes_target = 1234;
Harald Alvestranda6544372023-11-13 09:33:562617 video_media_info.senders[0].total_packet_send_delay = TimeDelta::Seconds(10);
Henrik Boströmce33b6a2019-05-28 15:42:382618 video_media_info.senders[0].quality_limitation_reason =
2619 QualityLimitationReason::kBandwidth;
Harald Alvestranda6544372023-11-13 09:33:562620 video_media_info.senders[0]
2621 .quality_limitation_durations_ms[QualityLimitationReason::kBandwidth] =
2622 300;
Evan Shrubsolecc62b162019-09-09 09:26:452623 video_media_info.senders[0].quality_limitation_resolution_changes = 56u;
Danil Chapovalov66cadcc2018-06-19 14:47:432624 video_media_info.senders[0].qp_sum = absl::nullopt;
Henrik Boström2e069262019-04-09 11:59:312625 video_media_info.senders[0].content_type = VideoContentType::UNSPECIFIED;
Philipp Hancke656817c2023-06-22 09:41:352626 video_media_info.senders[0].encoder_implementation_name = absl::nullopt;
Evan Shrubsole13c0be42022-10-31 11:03:102627 video_media_info.senders[0].power_efficient_encoder = false;
Henrik Boströma0ff50c2020-05-05 13:54:462628 video_media_info.senders[0].send_frame_width = 200;
2629 video_media_info.senders[0].send_frame_height = 100;
2630 video_media_info.senders[0].framerate_sent = 10;
2631 video_media_info.senders[0].frames_sent = 5;
2632 video_media_info.senders[0].huge_frames_sent = 2;
Philipp Hancke684e2412022-07-28 10:41:002633 video_media_info.senders[0].active = false;
Evan Shrubsole9b235cd2022-12-06 10:09:102634 video_media_info.senders[0].scalability_mode = ScalabilityMode::kL3T3_KEY;
Philipp Hancke9b82b2f2023-07-28 10:27:132635 video_media_info.senders[0].ssrc_groups.push_back(
2636 {cricket::kFidSsrcGroupSemantics, {1, 4404}});
Henrik Boströma0ff50c2020-05-05 13:54:462637 video_media_info.aggregated_senders.push_back(video_media_info.senders[0]);
hbos0adb8282016-11-23 10:32:062638 RtpCodecParameters codec_parameters;
2639 codec_parameters.payload_type = 42;
deadbeefe702b302017-02-04 20:09:012640 codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
2641 codec_parameters.name = "dummy";
Oskar Sundbomcbc71b22017-11-16 09:56:072642 codec_parameters.clock_rate = 0;
hbos0adb8282016-11-23 10:32:062643 video_media_info.send_codecs.insert(
2644 std::make_pair(codec_parameters.payload_type, codec_parameters));
2645
Harald Alvestrand2f553702023-03-07 10:10:032646 auto video_media_channels =
Tommi19015512022-02-02 10:49:352647 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Steve Anton5b387312018-02-03 00:00:202648 stats_->SetupLocalTrackAndSender(cricket::MEDIA_TYPE_VIDEO,
Henrik Boström646fda02019-05-22 13:49:422649 "LocalVideoTrackID", 1, true,
2650 /*attachment_id=*/50);
hbos6ded1902016-11-01 08:50:462651
Steve Anton5b387312018-02-03 00:00:202652 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos6ded1902016-11-01 08:50:462653
Philipp Hancke1f98b462023-03-07 08:53:592654 auto stats_of_my_type = report->GetStatsOfType<RTCOutboundRtpStreamStats>();
Mirko Bonadeie12c1fe2018-07-03 10:53:232655 ASSERT_EQ(1U, stats_of_my_type.size());
Harald Alvestranda3dab842018-01-14 08:18:582656
Philipp Hancke1f98b462023-03-07 08:53:592657 RTCOutboundRtpStreamStats expected_video(stats_of_my_type[0]->id(),
Philipp Hanckeb81823a2023-01-04 14:17:422658 report->timestamp());
Henrik Boström8dfc90f2022-09-02 07:39:292659 expected_video.media_source_id = "SV50";
Artem Titovcfea2182021-08-09 23:22:312660 // `expected_video.remote_id` should be undefined.
Henrik Boström1ab61882022-06-16 15:07:332661 expected_video.mid = "VideoMid";
hbos3443bb72017-02-07 14:28:112662 expected_video.ssrc = 1;
Philipp Hancke3bc01662018-08-28 12:55:032663 expected_video.kind = "video";
Henrik Boström8dfc90f2022-09-02 07:39:292664 expected_video.transport_id = "TTransportName1";
2665 expected_video.codec_id = "COTTransportName1_42";
hbos6ded1902016-11-01 08:50:462666 expected_video.fir_count = 2;
2667 expected_video.pli_count = 3;
2668 expected_video.nack_count = 4;
2669 expected_video.packets_sent = 5;
Henrik Boströmcf96e0f2019-04-17 11:51:532670 expected_video.retransmitted_packets_sent = 50;
hbos6ded1902016-11-01 08:50:462671 expected_video.bytes_sent = 6;
Niels Möllerac0a4cb2019-10-09 13:01:332672 expected_video.header_bytes_sent = 12;
Henrik Boströmcf96e0f2019-04-17 11:51:532673 expected_video.retransmitted_bytes_sent = 60;
skvladed02c6d2017-02-07 18:45:312674 expected_video.frames_encoded = 8;
Rasmus Brandt2efae772019-06-27 12:29:342675 expected_video.key_frames_encoded = 3;
Henrik Boströmf71362f2019-04-08 14:14:232676 expected_video.total_encode_time = 9.0;
Henrik Boström23aff9b2019-05-20 13:15:382677 expected_video.total_encoded_bytes_target = 1234;
Henrik Boström9fe18342019-05-16 16:38:202678 expected_video.total_packet_send_delay = 10.0;
Henrik Boströmce33b6a2019-05-28 15:42:382679 expected_video.quality_limitation_reason = "bandwidth";
Byoungchan Lee7d235352021-05-28 12:32:042680 expected_video.quality_limitation_durations = std::map<std::string, double>{
Philipp Hancke3fd9cbc2022-01-10 16:41:432681 std::pair<std::string, double>{"bandwidth", 0.3},
Byoungchan Lee7d235352021-05-28 12:32:042682 };
Evan Shrubsolecc62b162019-09-09 09:26:452683 expected_video.quality_limitation_resolution_changes = 56u;
Eldar Rello9276e2c2020-06-10 14:53:392684 expected_video.frame_width = 200u;
2685 expected_video.frame_height = 100u;
2686 expected_video.frames_per_second = 10.0;
2687 expected_video.frames_sent = 5;
2688 expected_video.huge_frames_sent = 2;
Philipp Hancke684e2412022-07-28 10:41:002689 expected_video.active = false;
Evan Shrubsole13c0be42022-10-31 11:03:102690 expected_video.power_efficient_encoder = false;
Evan Shrubsole9b235cd2022-12-06 10:09:102691 expected_video.scalability_mode = "L3T3_KEY";
Philipp Hancke9b82b2f2023-07-28 10:27:132692 expected_video.rtx_ssrc = 4404;
Artem Titovcfea2182021-08-09 23:22:312693 // `expected_video.content_type` should be undefined.
2694 // `expected_video.qp_sum` should be undefined.
2695 // `expected_video.encoder_implementation` should be undefined.
hboscd195be2017-02-07 16:31:272696 ASSERT_TRUE(report->Get(expected_video.id()));
Harald Alvestranda3dab842018-01-14 08:18:582697
hbosa51d4f32017-02-16 13:34:482698 EXPECT_EQ(
Philipp Hancke1f98b462023-03-07 08:53:592699 report->Get(expected_video.id())->cast_to<RTCOutboundRtpStreamStats>(),
hbosa51d4f32017-02-16 13:34:482700 expected_video);
skvladed02c6d2017-02-07 18:45:312701
hbosa51d4f32017-02-16 13:34:482702 // Set previously undefined values and "GetStats" again.
Oskar Sundbomcbc71b22017-11-16 09:56:072703 video_media_info.senders[0].qp_sum = 9;
hbosa51d4f32017-02-16 13:34:482704 expected_video.qp_sum = 9;
Henrik Boström2e069262019-04-09 11:59:312705 video_media_info.senders[0].content_type = VideoContentType::SCREENSHARE;
2706 expected_video.content_type = "screenshare";
Henrik Boström6b430862019-08-16 11:09:512707 video_media_info.senders[0].encoder_implementation_name = "libfooencoder";
Henrik Boströma0ff50c2020-05-05 13:54:462708 video_media_info.aggregated_senders[0] = video_media_info.senders[0];
Henrik Boström6b430862019-08-16 11:09:512709 expected_video.encoder_implementation = "libfooencoder";
Evan Shrubsole13c0be42022-10-31 11:03:102710 video_media_info.senders[0].power_efficient_encoder = true;
2711 expected_video.power_efficient_encoder = true;
Harald Alvestrand2f553702023-03-07 10:10:032712 video_media_channels.first->SetStats(video_media_info);
2713 video_media_channels.second->SetStats(video_media_info);
hbosa51d4f32017-02-16 13:34:482714
Steve Anton5b387312018-02-03 00:00:202715 report = stats_->GetFreshStatsReport();
hbosa51d4f32017-02-16 13:34:482716
2717 ASSERT_TRUE(report->Get(expected_video.id()));
2718 EXPECT_EQ(
Philipp Hancke1f98b462023-03-07 08:53:592719 report->Get(expected_video.id())->cast_to<RTCOutboundRtpStreamStats>(),
hbosa51d4f32017-02-16 13:34:482720 expected_video);
hbos84abeb12017-01-16 14:16:442721 EXPECT_TRUE(report->Get(*expected_video.transport_id));
2722 EXPECT_TRUE(report->Get(*expected_video.codec_id));
hbos6ded1902016-11-01 08:50:462723}
2724
hbos2fa7c672016-10-24 11:00:052725TEST_F(RTCStatsCollectorTest, CollectRTCTransportStats) {
Steve Anton5b387312018-02-03 00:00:202726 const char kTransportName[] = "transport";
2727
2728 pc_->AddVoiceChannel("audio", kTransportName);
2729
Gary Liu37e489c2017-11-21 18:49:362730 std::unique_ptr<cricket::Candidate> rtp_local_candidate =
2731 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
2732 cricket::LOCAL_PORT_TYPE, 42);
hbos2fa7c672016-10-24 11:00:052733 std::unique_ptr<cricket::Candidate> rtp_remote_candidate =
2734 CreateFakeCandidate("42.42.42.42", 42, "protocol",
Gary Liu37e489c2017-11-21 18:49:362735 rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
2736 42);
hbos2fa7c672016-10-24 11:00:052737 std::unique_ptr<cricket::Candidate> rtcp_local_candidate =
Gary Liu37e489c2017-11-21 18:49:362738 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
hbos2fa7c672016-10-24 11:00:052739 cricket::LOCAL_PORT_TYPE, 42);
2740 std::unique_ptr<cricket::Candidate> rtcp_remote_candidate =
2741 CreateFakeCandidate("42.42.42.42", 42, "protocol",
Gary Liu37e489c2017-11-21 18:49:362742 rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
2743 42);
hbos2fa7c672016-10-24 11:00:052744
hbos2fa7c672016-10-24 11:00:052745 cricket::ConnectionInfo rtp_connection_info;
2746 rtp_connection_info.best_connection = false;
2747 rtp_connection_info.local_candidate = *rtp_local_candidate.get();
2748 rtp_connection_info.remote_candidate = *rtp_remote_candidate.get();
2749 rtp_connection_info.sent_total_bytes = 42;
2750 rtp_connection_info.recv_total_bytes = 1337;
Artem Titovedacbd52020-07-06 14:06:372751 rtp_connection_info.sent_total_packets = 3;
2752 rtp_connection_info.sent_discarded_packets = 2;
2753 rtp_connection_info.packets_received = 4;
hbos2fa7c672016-10-24 11:00:052754 cricket::TransportChannelStats rtp_transport_channel_stats;
2755 rtp_transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
Jonas Oreland149dc722019-08-28 06:10:272756 rtp_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
2757 rtp_connection_info);
Mirko Bonadei9f6808b2021-05-21 18:46:092758 rtp_transport_channel_stats.dtls_state = DtlsTransportState::kNew;
Jonas Oreland42da5a92022-03-01 12:55:372759 rtp_transport_channel_stats.ice_transport_stats.bytes_sent = 42;
2760 rtp_transport_channel_stats.ice_transport_stats.packets_sent = 1;
2761 rtp_transport_channel_stats.ice_transport_stats.bytes_received = 1337;
2762 rtp_transport_channel_stats.ice_transport_stats.packets_received = 4;
Jonas Oreland149dc722019-08-28 06:10:272763 rtp_transport_channel_stats.ice_transport_stats
2764 .selected_candidate_pair_changes = 1;
Philipp Hancke95b1a342022-05-05 05:53:542765 rtp_transport_channel_stats.ice_transport_stats.ice_local_username_fragment =
2766 "thelocalufrag";
Steve Anton5b387312018-02-03 00:00:202767 pc_->SetTransportStats(kTransportName, {rtp_transport_channel_stats});
hbos2fa7c672016-10-24 11:00:052768
2769 // Get stats without RTCP, an active connection or certificates.
Steve Anton5b387312018-02-03 00:00:202770 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos0583b282016-11-30 09:50:142771
2772 RTCTransportStats expected_rtp_transport(
Henrik Boström8dfc90f2022-09-02 07:39:292773 "Ttransport" + rtc::ToString(cricket::ICE_CANDIDATE_COMPONENT_RTP),
Philipp Hanckeb81823a2023-01-04 14:17:422774 report->timestamp());
hbos0583b282016-11-30 09:50:142775 expected_rtp_transport.bytes_sent = 42;
Artem Titovedacbd52020-07-06 14:06:372776 expected_rtp_transport.packets_sent = 1;
hbos0583b282016-11-30 09:50:142777 expected_rtp_transport.bytes_received = 1337;
Artem Titovedacbd52020-07-06 14:06:372778 expected_rtp_transport.packets_received = 4;
Henrik Boströmc929ab42023-06-15 13:17:452779 expected_rtp_transport.dtls_state = "new";
2780 expected_rtp_transport.dtls_role = "unknown";
Jonas Oreland149dc722019-08-28 06:10:272781 expected_rtp_transport.selected_candidate_pair_changes = 1;
Henrik Boströmc929ab42023-06-15 13:17:452782 expected_rtp_transport.ice_role = "unknown";
Philipp Hancke95b1a342022-05-05 05:53:542783 expected_rtp_transport.ice_local_username_fragment = "thelocalufrag";
Henrik Boströmc929ab42023-06-15 13:17:452784 expected_rtp_transport.ice_state = "new";
hbos0583b282016-11-30 09:50:142785
hbosdbb64d82016-12-21 09:57:462786 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
hbos0583b282016-11-30 09:50:142787 EXPECT_EQ(
2788 expected_rtp_transport,
2789 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
hbos2fa7c672016-10-24 11:00:052790
2791 cricket::ConnectionInfo rtcp_connection_info;
2792 rtcp_connection_info.best_connection = false;
2793 rtcp_connection_info.local_candidate = *rtcp_local_candidate.get();
2794 rtcp_connection_info.remote_candidate = *rtcp_remote_candidate.get();
2795 rtcp_connection_info.sent_total_bytes = 1337;
2796 rtcp_connection_info.recv_total_bytes = 42;
Artem Titovedacbd52020-07-06 14:06:372797 rtcp_connection_info.sent_total_packets = 3;
2798 rtcp_connection_info.sent_discarded_packets = 2;
2799 rtcp_connection_info.packets_received = 4;
hbos2fa7c672016-10-24 11:00:052800 cricket::TransportChannelStats rtcp_transport_channel_stats;
2801 rtcp_transport_channel_stats.component =
2802 cricket::ICE_CANDIDATE_COMPONENT_RTCP;
Jonas Oreland149dc722019-08-28 06:10:272803 rtcp_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
2804 rtcp_connection_info);
Mirko Bonadei9f6808b2021-05-21 18:46:092805 rtcp_transport_channel_stats.dtls_state = DtlsTransportState::kConnecting;
Jonas Oreland42da5a92022-03-01 12:55:372806 rtcp_transport_channel_stats.ice_transport_stats.bytes_sent = 1337;
2807 rtcp_transport_channel_stats.ice_transport_stats.packets_sent = 1;
2808 rtcp_transport_channel_stats.ice_transport_stats.bytes_received = 42;
2809 rtcp_transport_channel_stats.ice_transport_stats.packets_received = 4;
Philipp Hancke95b1a342022-05-05 05:53:542810 rtcp_transport_channel_stats.ice_transport_stats.ice_local_username_fragment =
2811 "thelocalufrag";
Philipp Hancke1f491572022-05-09 15:43:312812 rtcp_transport_channel_stats.ice_transport_stats.ice_state =
2813 IceTransportState::kChecking;
Steve Anton5b387312018-02-03 00:00:202814 pc_->SetTransportStats(kTransportName, {rtp_transport_channel_stats,
2815 rtcp_transport_channel_stats});
hbos2fa7c672016-10-24 11:00:052816
hbos2fa7c672016-10-24 11:00:052817 // Get stats with RTCP and without an active connection or certificates.
Steve Anton5b387312018-02-03 00:00:202818 report = stats_->GetFreshStatsReport();
hbos0583b282016-11-30 09:50:142819
2820 RTCTransportStats expected_rtcp_transport(
Henrik Boström8dfc90f2022-09-02 07:39:292821 "Ttransport" + rtc::ToString(cricket::ICE_CANDIDATE_COMPONENT_RTCP),
Philipp Hanckeb81823a2023-01-04 14:17:422822 report->timestamp());
hbos0583b282016-11-30 09:50:142823 expected_rtcp_transport.bytes_sent = 1337;
Artem Titovedacbd52020-07-06 14:06:372824 expected_rtcp_transport.packets_sent = 1;
hbos0583b282016-11-30 09:50:142825 expected_rtcp_transport.bytes_received = 42;
Artem Titovedacbd52020-07-06 14:06:372826 expected_rtcp_transport.packets_received = 4;
Henrik Boströmc929ab42023-06-15 13:17:452827 expected_rtcp_transport.dtls_state = "connecting";
2828 expected_rtcp_transport.dtls_role = "unknown";
Jonas Oreland149dc722019-08-28 06:10:272829 expected_rtcp_transport.selected_candidate_pair_changes = 0;
Henrik Boströmc929ab42023-06-15 13:17:452830 expected_rtcp_transport.ice_role = "unknown";
Philipp Hancke95b1a342022-05-05 05:53:542831 expected_rtcp_transport.ice_local_username_fragment = "thelocalufrag";
Henrik Boströmc929ab42023-06-15 13:17:452832 expected_rtcp_transport.ice_state = "checking";
hbos0583b282016-11-30 09:50:142833
2834 expected_rtp_transport.rtcp_transport_stats_id = expected_rtcp_transport.id();
hbosdbb64d82016-12-21 09:57:462835 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
hbos0583b282016-11-30 09:50:142836 EXPECT_EQ(
2837 expected_rtp_transport,
2838 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
hbosdbb64d82016-12-21 09:57:462839 ASSERT_TRUE(report->Get(expected_rtcp_transport.id()));
hbos0583b282016-11-30 09:50:142840 EXPECT_EQ(
2841 expected_rtcp_transport,
2842 report->Get(expected_rtcp_transport.id())->cast_to<RTCTransportStats>());
hbos2fa7c672016-10-24 11:00:052843
hbos7064d592017-01-16 15:38:022844 // Get stats with an active connection (selected candidate pair).
Jonas Oreland149dc722019-08-28 06:10:272845 rtcp_transport_channel_stats.ice_transport_stats.connection_infos[0]
2846 .best_connection = true;
Steve Anton5b387312018-02-03 00:00:202847 pc_->SetTransportStats(kTransportName, {rtp_transport_channel_stats,
2848 rtcp_transport_channel_stats});
hbos2fa7c672016-10-24 11:00:052849
Steve Anton5b387312018-02-03 00:00:202850 report = stats_->GetFreshStatsReport();
hbos0583b282016-11-30 09:50:142851
hbos0583b282016-11-30 09:50:142852 expected_rtcp_transport.selected_candidate_pair_id =
Henrik Boström8dfc90f2022-09-02 07:39:292853 "CP" + rtcp_local_candidate->id() + "_" + rtcp_remote_candidate->id();
hbos0583b282016-11-30 09:50:142854
hbosdbb64d82016-12-21 09:57:462855 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
hbos0583b282016-11-30 09:50:142856 EXPECT_EQ(
2857 expected_rtp_transport,
2858 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
hbosdbb64d82016-12-21 09:57:462859 ASSERT_TRUE(report->Get(expected_rtcp_transport.id()));
hbos0583b282016-11-30 09:50:142860 EXPECT_EQ(
2861 expected_rtcp_transport,
2862 report->Get(expected_rtcp_transport.id())->cast_to<RTCTransportStats>());
hbos2fa7c672016-10-24 11:00:052863
2864 // Get stats with certificates.
2865 std::unique_ptr<CertificateInfo> local_certinfo =
Steve Anton5b387312018-02-03 00:00:202866 CreateFakeCertificateAndInfoFromDers({"(local) local", "(local) chain"});
2867 pc_->SetLocalCertificate(kTransportName, local_certinfo->certificate);
hbos2fa7c672016-10-24 11:00:052868 std::unique_ptr<CertificateInfo> remote_certinfo =
2869 CreateFakeCertificateAndInfoFromDers(
Steve Anton5b387312018-02-03 00:00:202870 {"(remote) local", "(remote) chain"});
Taylor Brandstetterc3928662018-02-23 21:04:512871 pc_->SetRemoteCertChain(
Benjamin Wright6c6c9df2018-10-25 08:16:262872 kTransportName,
2873 remote_certinfo->certificate->GetSSLCertificateChain().Clone());
hbos2fa7c672016-10-24 11:00:052874
Steve Anton5b387312018-02-03 00:00:202875 report = stats_->GetFreshStatsReport();
hbos0583b282016-11-30 09:50:142876
2877 expected_rtp_transport.local_certificate_id =
Henrik Boström8dfc90f2022-09-02 07:39:292878 "CF" + local_certinfo->fingerprints[0];
hbos0583b282016-11-30 09:50:142879 expected_rtp_transport.remote_certificate_id =
Henrik Boström8dfc90f2022-09-02 07:39:292880 "CF" + remote_certinfo->fingerprints[0];
hbos0583b282016-11-30 09:50:142881
2882 expected_rtcp_transport.local_certificate_id =
2883 *expected_rtp_transport.local_certificate_id;
2884 expected_rtcp_transport.remote_certificate_id =
2885 *expected_rtp_transport.remote_certificate_id;
2886
hbosdbb64d82016-12-21 09:57:462887 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
hbos0583b282016-11-30 09:50:142888 EXPECT_EQ(
2889 expected_rtp_transport,
2890 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
hbosdbb64d82016-12-21 09:57:462891 ASSERT_TRUE(report->Get(expected_rtcp_transport.id()));
hbos0583b282016-11-30 09:50:142892 EXPECT_EQ(
2893 expected_rtcp_transport,
2894 report->Get(expected_rtcp_transport.id())->cast_to<RTCTransportStats>());
hbos2fa7c672016-10-24 11:00:052895}
2896
Harald Alvestrand5cb78072019-10-28 08:51:172897TEST_F(RTCStatsCollectorTest, CollectRTCTransportStatsWithCrypto) {
2898 const char kTransportName[] = "transport";
2899
2900 pc_->AddVoiceChannel("audio", kTransportName);
2901
2902 std::unique_ptr<cricket::Candidate> rtp_local_candidate =
2903 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
2904 cricket::LOCAL_PORT_TYPE, 42);
2905 std::unique_ptr<cricket::Candidate> rtp_remote_candidate =
2906 CreateFakeCandidate("42.42.42.42", 42, "protocol",
2907 rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
2908 42);
2909 std::unique_ptr<cricket::Candidate> rtcp_local_candidate =
2910 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
2911 cricket::LOCAL_PORT_TYPE, 42);
2912 std::unique_ptr<cricket::Candidate> rtcp_remote_candidate =
2913 CreateFakeCandidate("42.42.42.42", 42, "protocol",
2914 rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
2915 42);
2916
2917 cricket::ConnectionInfo rtp_connection_info;
2918 rtp_connection_info.best_connection = false;
2919 rtp_connection_info.local_candidate = *rtp_local_candidate.get();
2920 rtp_connection_info.remote_candidate = *rtp_remote_candidate.get();
Harald Alvestrand5cb78072019-10-28 08:51:172921 cricket::TransportChannelStats rtp_transport_channel_stats;
2922 rtp_transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
2923 rtp_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
2924 rtp_connection_info);
2925 // The state must be connected in order for crypto parameters to show up.
Mirko Bonadei9f6808b2021-05-21 18:46:092926 rtp_transport_channel_stats.dtls_state = DtlsTransportState::kConnected;
Harald Alvestrand5cb78072019-10-28 08:51:172927 rtp_transport_channel_stats.ice_transport_stats
2928 .selected_candidate_pair_changes = 1;
2929 rtp_transport_channel_stats.ssl_version_bytes = 0x0203;
Philipp Hancke69c1df22022-04-22 13:46:242930 rtp_transport_channel_stats.dtls_role = rtc::SSL_CLIENT;
Philipp Hanckecc1b9b02022-05-04 16:58:262931 rtp_transport_channel_stats.ice_transport_stats.ice_role =
2932 cricket::ICEROLE_CONTROLLING;
Philipp Hancke95b1a342022-05-05 05:53:542933 rtp_transport_channel_stats.ice_transport_stats.ice_local_username_fragment =
2934 "thelocalufrag";
Philipp Hancke1f491572022-05-09 15:43:312935 rtp_transport_channel_stats.ice_transport_stats.ice_state =
2936 IceTransportState::kConnected;
Harald Alvestrand5cb78072019-10-28 08:51:172937 // 0x2F is TLS_RSA_WITH_AES_128_CBC_SHA according to IANA
2938 rtp_transport_channel_stats.ssl_cipher_suite = 0x2F;
Mirko Bonadei7750d802021-07-26 15:27:422939 rtp_transport_channel_stats.srtp_crypto_suite = rtc::kSrtpAes128CmSha1_80;
Harald Alvestrand5cb78072019-10-28 08:51:172940 pc_->SetTransportStats(kTransportName, {rtp_transport_channel_stats});
2941
2942 // Get stats
2943 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
2944
2945 RTCTransportStats expected_rtp_transport(
Henrik Boström8dfc90f2022-09-02 07:39:292946 "Ttransport" + rtc::ToString(cricket::ICE_CANDIDATE_COMPONENT_RTP),
Philipp Hanckeb81823a2023-01-04 14:17:422947 report->timestamp());
Henrik Boströmc929ab42023-06-15 13:17:452948 expected_rtp_transport.dtls_state = "connected";
Harald Alvestrand5cb78072019-10-28 08:51:172949 expected_rtp_transport.selected_candidate_pair_changes = 1;
Henrik Boströmc929ab42023-06-15 13:17:452950 expected_rtp_transport.ice_role = "unknown";
Jonas Oreland42da5a92022-03-01 12:55:372951 expected_rtp_transport.bytes_sent = 0;
2952 expected_rtp_transport.bytes_received = 0;
2953 expected_rtp_transport.packets_sent = 0;
2954 expected_rtp_transport.packets_received = 0;
Henrik Boströmc929ab42023-06-15 13:17:452955 expected_rtp_transport.ice_role = "controlling";
Philipp Hancke95b1a342022-05-05 05:53:542956 expected_rtp_transport.ice_local_username_fragment = "thelocalufrag";
Philipp Hancke1f491572022-05-09 15:43:312957 expected_rtp_transport.ice_state = "connected";
Harald Alvestrand5cb78072019-10-28 08:51:172958 // Crypto parameters
2959 expected_rtp_transport.tls_version = "0203";
Henrik Boströmc929ab42023-06-15 13:17:452960 expected_rtp_transport.dtls_role = "client";
Harald Alvestrand5cb78072019-10-28 08:51:172961 expected_rtp_transport.dtls_cipher = "TLS_RSA_WITH_AES_128_CBC_SHA";
2962 expected_rtp_transport.srtp_cipher = "AES_CM_128_HMAC_SHA1_80";
2963
2964 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
2965 EXPECT_EQ(
2966 expected_rtp_transport,
2967 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
2968}
2969
Philipp Hancke1f98b462023-03-07 08:53:592970TEST_F(RTCStatsCollectorTest, CollectNoStreamRTCOutboundRtpStreamStats_Audio) {
Harald Alvestrand89061872018-01-02 13:08:342971 cricket::VoiceMediaInfo voice_media_info;
2972
2973 voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
2974 voice_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
2975 voice_media_info.senders[0].local_stats[0].ssrc = 1;
2976 voice_media_info.senders[0].packets_sent = 2;
Henrik Boströmaebba7b2022-10-26 14:53:032977 voice_media_info.senders[0].total_packet_send_delay = TimeDelta::Seconds(0.5);
Henrik Boströmcf96e0f2019-04-17 11:51:532978 voice_media_info.senders[0].retransmitted_packets_sent = 20;
Niels Möllerac0a4cb2019-10-09 13:01:332979 voice_media_info.senders[0].payload_bytes_sent = 3;
2980 voice_media_info.senders[0].header_and_padding_bytes_sent = 4;
Henrik Boströmcf96e0f2019-04-17 11:51:532981 voice_media_info.senders[0].retransmitted_bytes_sent = 30;
Philipp Hancke6a7bf102023-04-21 17:32:422982 voice_media_info.senders[0].nacks_received = 31;
Harald Alvestrand89061872018-01-02 13:08:342983 voice_media_info.senders[0].codec_payload_type = 42;
Philipp Hancke684e2412022-07-28 10:41:002984 voice_media_info.senders[0].active = true;
Harald Alvestrand89061872018-01-02 13:08:342985
2986 RtpCodecParameters codec_parameters;
2987 codec_parameters.payload_type = 42;
2988 codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
2989 codec_parameters.name = "dummy";
2990 codec_parameters.clock_rate = 0;
2991 voice_media_info.send_codecs.insert(
2992 std::make_pair(codec_parameters.payload_type, codec_parameters));
2993
Steve Anton5b387312018-02-03 00:00:202994 // Emulates the case where AddTrack is used without an associated MediaStream
Tommi19015512022-02-02 10:49:352995 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Steve Anton5b387312018-02-03 00:00:202996 stats_->SetupLocalTrackAndSender(cricket::MEDIA_TYPE_AUDIO,
Henrik Boström646fda02019-05-22 13:49:422997 "LocalAudioTrackID", 1, false,
2998 /*attachment_id=*/50);
Harald Alvestrand89061872018-01-02 13:08:342999
Steve Anton5b387312018-02-03 00:00:203000 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Harald Alvestrand89061872018-01-02 13:08:343001
Philipp Hancke1f98b462023-03-07 08:53:593002 RTCOutboundRtpStreamStats expected_audio("OTTransportName1A1",
Philipp Hanckeb81823a2023-01-04 14:17:423003 report->timestamp());
Henrik Boström8dfc90f2022-09-02 07:39:293004 expected_audio.media_source_id = "SA50";
Henrik Boström1ab61882022-06-16 15:07:333005 expected_audio.mid = "AudioMid";
Harald Alvestrand89061872018-01-02 13:08:343006 expected_audio.ssrc = 1;
Philipp Hancke3bc01662018-08-28 12:55:033007 expected_audio.kind = "audio";
Henrik Boström8dfc90f2022-09-02 07:39:293008 expected_audio.transport_id = "TTransportName1";
3009 expected_audio.codec_id = "COTTransportName1_42";
Harald Alvestrand89061872018-01-02 13:08:343010 expected_audio.packets_sent = 2;
Henrik Boströmaebba7b2022-10-26 14:53:033011 expected_audio.total_packet_send_delay = 0.5;
Henrik Boströmcf96e0f2019-04-17 11:51:533012 expected_audio.retransmitted_packets_sent = 20;
Harald Alvestrand89061872018-01-02 13:08:343013 expected_audio.bytes_sent = 3;
Niels Möllerac0a4cb2019-10-09 13:01:333014 expected_audio.header_bytes_sent = 4;
Henrik Boströmcf96e0f2019-04-17 11:51:533015 expected_audio.retransmitted_bytes_sent = 30;
Jakob Ivarssone91c9922021-07-06 07:55:433016 expected_audio.nack_count = 31;
Philipp Hancke684e2412022-07-28 10:41:003017 expected_audio.active = true;
Harald Alvestrand89061872018-01-02 13:08:343018
3019 ASSERT_TRUE(report->Get(expected_audio.id()));
3020 EXPECT_EQ(
Philipp Hancke1f98b462023-03-07 08:53:593021 report->Get(expected_audio.id())->cast_to<RTCOutboundRtpStreamStats>(),
Harald Alvestrand89061872018-01-02 13:08:343022 expected_audio);
Harald Alvestrand89061872018-01-02 13:08:343023 EXPECT_TRUE(report->Get(*expected_audio.transport_id));
3024 EXPECT_TRUE(report->Get(*expected_audio.codec_id));
3025}
3026
Henrik Boström646fda02019-05-22 13:49:423027TEST_F(RTCStatsCollectorTest, RTCAudioSourceStatsCollectedForSenderWithTrack) {
3028 const uint32_t kSsrc = 4;
3029 const int kAttachmentId = 42;
3030
3031 cricket::VoiceMediaInfo voice_media_info;
3032 voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
3033 voice_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3034 voice_media_info.senders[0].local_stats[0].ssrc = kSsrc;
Henrik Boströmd2c336f2019-07-03 15:11:103035 voice_media_info.senders[0].audio_level = 32767; // [0,32767]
3036 voice_media_info.senders[0].total_input_energy = 2.0;
3037 voice_media_info.senders[0].total_input_duration = 3.0;
Taylor Brandstetter64851c02021-06-24 20:32:503038 voice_media_info.senders[0].apm_statistics.echo_return_loss = 42.0;
3039 voice_media_info.senders[0].apm_statistics.echo_return_loss_enhancement =
3040 52.0;
Tommi19015512022-02-02 10:49:353041 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Henrik Boström646fda02019-05-22 13:49:423042 stats_->SetupLocalTrackAndSender(cricket::MEDIA_TYPE_AUDIO,
3043 "LocalAudioTrackID", kSsrc, false,
3044 kAttachmentId);
3045
3046 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3047
Philipp Hanckeb81823a2023-01-04 14:17:423048 RTCAudioSourceStats expected_audio("SA42", report->timestamp());
Henrik Boström646fda02019-05-22 13:49:423049 expected_audio.track_identifier = "LocalAudioTrackID";
3050 expected_audio.kind = "audio";
Henrik Boströmd2c336f2019-07-03 15:11:103051 expected_audio.audio_level = 1.0; // [0,1]
3052 expected_audio.total_audio_energy = 2.0;
3053 expected_audio.total_samples_duration = 3.0;
Taylor Brandstetter64851c02021-06-24 20:32:503054 expected_audio.echo_return_loss = 42.0;
3055 expected_audio.echo_return_loss_enhancement = 52.0;
Henrik Boström646fda02019-05-22 13:49:423056
3057 ASSERT_TRUE(report->Get(expected_audio.id()));
3058 EXPECT_EQ(report->Get(expected_audio.id())->cast_to<RTCAudioSourceStats>(),
3059 expected_audio);
3060}
3061
3062TEST_F(RTCStatsCollectorTest, RTCVideoSourceStatsCollectedForSenderWithTrack) {
3063 const uint32_t kSsrc = 4;
3064 const int kAttachmentId = 42;
3065 const int kVideoSourceWidth = 12;
3066 const int kVideoSourceHeight = 34;
3067
3068 cricket::VideoMediaInfo video_media_info;
Henrik Boströma0ff50c2020-05-05 13:54:463069 video_media_info.aggregated_senders.push_back(cricket::VideoSenderInfo());
Henrik Boström646fda02019-05-22 13:49:423070 video_media_info.senders.push_back(cricket::VideoSenderInfo());
3071 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3072 video_media_info.senders[0].local_stats[0].ssrc = kSsrc;
Byoungchan Leeefe46b62021-11-10 02:23:563073 video_media_info.senders[0].framerate_input = 29.0;
Henrik Boströma0ff50c2020-05-05 13:54:463074 video_media_info.aggregated_senders[0].local_stats.push_back(
3075 cricket::SsrcSenderInfo());
3076 video_media_info.aggregated_senders[0].local_stats[0].ssrc = kSsrc;
Byoungchan Leeefe46b62021-11-10 02:23:563077 video_media_info.aggregated_senders[0].framerate_input = 29.0;
Di Wu668dbf62021-02-27 08:29:153078 video_media_info.aggregated_senders[0].frames = 10001;
Tommi19015512022-02-02 10:49:353079 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström646fda02019-05-22 13:49:423080
3081 auto video_source = FakeVideoTrackSourceForStats::Create(kVideoSourceWidth,
3082 kVideoSourceHeight);
3083 auto video_track = FakeVideoTrackForStats::Create(
3084 "LocalVideoTrackID", MediaStreamTrackInterface::kLive, video_source);
3085 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
3086 cricket::MEDIA_TYPE_VIDEO, video_track, kSsrc, kAttachmentId, {});
Tommi6589def2022-02-17 22:36:473087 EXPECT_CALL(*sender, Stop());
3088 EXPECT_CALL(*sender, SetMediaChannel(_));
Henrik Boström646fda02019-05-22 13:49:423089 pc_->AddSender(sender);
3090
3091 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3092
Philipp Hanckeb81823a2023-01-04 14:17:423093 RTCVideoSourceStats expected_video("SV42", report->timestamp());
Henrik Boström646fda02019-05-22 13:49:423094 expected_video.track_identifier = "LocalVideoTrackID";
3095 expected_video.kind = "video";
3096 expected_video.width = kVideoSourceWidth;
3097 expected_video.height = kVideoSourceHeight;
Byoungchan Leeefe46b62021-11-10 02:23:563098 expected_video.frames_per_second = 29.0;
Di Wu668dbf62021-02-27 08:29:153099 expected_video.frames = 10001;
Henrik Boström646fda02019-05-22 13:49:423100
3101 ASSERT_TRUE(report->Get(expected_video.id()));
3102 EXPECT_EQ(report->Get(expected_video.id())->cast_to<RTCVideoSourceStats>(),
3103 expected_video);
3104}
3105
3106// This test exercises the current behavior and code path, but the correct
3107// behavior is to report frame rate even if we have no SSRC.
3108// TODO(hbos): When we know the frame rate even if we have no SSRC, update the
3109// expectations of this test.
3110TEST_F(RTCStatsCollectorTest,
3111 RTCVideoSourceStatsMissingFrameRateWhenSenderHasNoSsrc) {
3112 // TODO(https://crbug.com/webrtc/8694): When 0 is no longer a magic value for
3113 // "none", update this test.
3114 const uint32_t kNoSsrc = 0;
3115 const int kAttachmentId = 42;
3116 const int kVideoSourceWidth = 12;
3117 const int kVideoSourceHeight = 34;
3118
3119 cricket::VideoMediaInfo video_media_info;
3120 video_media_info.senders.push_back(cricket::VideoSenderInfo());
3121 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
Byoungchan Leeefe46b62021-11-10 02:23:563122 video_media_info.senders[0].framerate_input = 29.0;
Tommi19015512022-02-02 10:49:353123 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström646fda02019-05-22 13:49:423124
3125 auto video_source = FakeVideoTrackSourceForStats::Create(kVideoSourceWidth,
3126 kVideoSourceHeight);
3127 auto video_track = FakeVideoTrackForStats::Create(
3128 "LocalVideoTrackID", MediaStreamTrackInterface::kLive, video_source);
3129 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
3130 cricket::MEDIA_TYPE_VIDEO, video_track, kNoSsrc, kAttachmentId, {});
Tommi6589def2022-02-17 22:36:473131 EXPECT_CALL(*sender, Stop());
3132 EXPECT_CALL(*sender, SetMediaChannel(_));
Henrik Boström646fda02019-05-22 13:49:423133 pc_->AddSender(sender);
3134
3135 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Henrik Boström8dfc90f2022-09-02 07:39:293136 ASSERT_TRUE(report->Get("SV42"));
3137 auto video_stats = report->Get("SV42")->cast_to<RTCVideoSourceStats>();
Henrik Boström646fda02019-05-22 13:49:423138 EXPECT_FALSE(video_stats.frames_per_second.is_defined());
Di Wu668dbf62021-02-27 08:29:153139 EXPECT_FALSE(video_stats.frames.is_defined());
Henrik Boström646fda02019-05-22 13:49:423140}
3141
3142// The track not having a source is not expected to be true in practise, but
3143// this is true in some tests relying on fakes. This test covers that code path.
3144TEST_F(RTCStatsCollectorTest,
3145 RTCVideoSourceStatsMissingResolutionWhenTrackHasNoSource) {
3146 const uint32_t kSsrc = 4;
3147 const int kAttachmentId = 42;
3148
3149 cricket::VideoMediaInfo video_media_info;
3150 video_media_info.senders.push_back(cricket::VideoSenderInfo());
3151 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3152 video_media_info.senders[0].local_stats[0].ssrc = kSsrc;
Byoungchan Leeefe46b62021-11-10 02:23:563153 video_media_info.senders[0].framerate_input = 29.0;
Tommi19015512022-02-02 10:49:353154 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström646fda02019-05-22 13:49:423155
3156 auto video_track = FakeVideoTrackForStats::Create(
3157 "LocalVideoTrackID", MediaStreamTrackInterface::kLive,
3158 /*source=*/nullptr);
3159 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
3160 cricket::MEDIA_TYPE_VIDEO, video_track, kSsrc, kAttachmentId, {});
Tommi6589def2022-02-17 22:36:473161 EXPECT_CALL(*sender, Stop());
3162 EXPECT_CALL(*sender, SetMediaChannel(_));
Henrik Boström646fda02019-05-22 13:49:423163 pc_->AddSender(sender);
3164
3165 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Henrik Boström8dfc90f2022-09-02 07:39:293166 ASSERT_TRUE(report->Get("SV42"));
3167 auto video_stats = report->Get("SV42")->cast_to<RTCVideoSourceStats>();
Henrik Boström646fda02019-05-22 13:49:423168 EXPECT_FALSE(video_stats.width.is_defined());
3169 EXPECT_FALSE(video_stats.height.is_defined());
3170}
3171
3172TEST_F(RTCStatsCollectorTest,
3173 RTCAudioSourceStatsNotCollectedForSenderWithoutTrack) {
3174 const uint32_t kSsrc = 4;
3175 const int kAttachmentId = 42;
3176
3177 cricket::VoiceMediaInfo voice_media_info;
3178 voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
3179 voice_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3180 voice_media_info.senders[0].local_stats[0].ssrc = kSsrc;
Tommi19015512022-02-02 10:49:353181 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Henrik Boström646fda02019-05-22 13:49:423182 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
3183 cricket::MEDIA_TYPE_AUDIO, /*track=*/nullptr, kSsrc, kAttachmentId, {});
Tommi6589def2022-02-17 22:36:473184 EXPECT_CALL(*sender, Stop());
3185 EXPECT_CALL(*sender, SetMediaChannel(_));
Henrik Boström646fda02019-05-22 13:49:423186 pc_->AddSender(sender);
3187
3188 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Henrik Boström8dfc90f2022-09-02 07:39:293189 EXPECT_FALSE(report->Get("SA42"));
Henrik Boström646fda02019-05-22 13:49:423190}
3191
Henrik Boström883eefc2019-05-27 11:40:253192// Parameterized tests on cricket::MediaType (audio or video).
3193class RTCStatsCollectorTestWithParamKind
3194 : public RTCStatsCollectorTest,
3195 public ::testing::WithParamInterface<cricket::MediaType> {
3196 public:
3197 RTCStatsCollectorTestWithParamKind() : media_type_(GetParam()) {
3198 RTC_DCHECK(media_type_ == cricket::MEDIA_TYPE_AUDIO ||
3199 media_type_ == cricket::MEDIA_TYPE_VIDEO);
3200 }
3201
Henrik Boström8dfc90f2022-09-02 07:39:293202 std::string MediaTypeCharStr() const {
Henrik Boström883eefc2019-05-27 11:40:253203 switch (media_type_) {
3204 case cricket::MEDIA_TYPE_AUDIO:
Henrik Boström8dfc90f2022-09-02 07:39:293205 return "A";
Henrik Boström883eefc2019-05-27 11:40:253206 case cricket::MEDIA_TYPE_VIDEO:
Henrik Boström8dfc90f2022-09-02 07:39:293207 return "V";
3208 case cricket::MEDIA_TYPE_DATA:
3209 case cricket::MEDIA_TYPE_UNSUPPORTED:
3210 RTC_DCHECK_NOTREACHED();
3211 return "?";
3212 }
3213 }
3214
3215 std::string MediaTypeKind() const {
3216 switch (media_type_) {
3217 case cricket::MEDIA_TYPE_AUDIO:
3218 return "audio";
3219 case cricket::MEDIA_TYPE_VIDEO:
3220 return "video";
Henrik Boström883eefc2019-05-27 11:40:253221 case cricket::MEDIA_TYPE_DATA:
Philipp Hancke4e8c1152020-10-13 10:43:153222 case cricket::MEDIA_TYPE_UNSUPPORTED:
Artem Titovd3251962021-11-15 15:57:073223 RTC_DCHECK_NOTREACHED();
Henrik Boström883eefc2019-05-27 11:40:253224 return "";
3225 }
3226 }
3227
Henrik Boström883eefc2019-05-27 11:40:253228 // Adds a sender and channel of the appropriate kind, creating a sender info
Artem Titov880fa812021-07-30 20:30:233229 // with the report block's `source_ssrc` and report block data.
Eldar Relloc07e9042020-07-03 08:08:073230 void AddSenderInfoAndMediaChannel(
3231 std::string transport_name,
3232 const std::vector<ReportBlockData>& report_block_datas,
3233 absl::optional<RtpCodecParameters> codec) {
Henrik Boström883eefc2019-05-27 11:40:253234 switch (media_type_) {
3235 case cricket::MEDIA_TYPE_AUDIO: {
3236 cricket::VoiceMediaInfo voice_media_info;
Eldar Relloc07e9042020-07-03 08:08:073237 for (const auto& report_block_data : report_block_datas) {
3238 cricket::VoiceSenderInfo sender;
3239 sender.local_stats.push_back(cricket::SsrcSenderInfo());
Danil Chapovalovd5b51672023-05-04 08:56:073240 sender.local_stats[0].ssrc = report_block_data.source_ssrc();
Eldar Relloc07e9042020-07-03 08:08:073241 if (codec.has_value()) {
3242 sender.codec_payload_type = codec->payload_type;
3243 voice_media_info.send_codecs.insert(
3244 std::make_pair(codec->payload_type, *codec));
3245 }
3246 sender.report_block_datas.push_back(report_block_data);
3247 voice_media_info.senders.push_back(sender);
Henrik Boström883eefc2019-05-27 11:40:253248 }
Tommi19015512022-02-02 10:49:353249 pc_->AddVoiceChannel("mid", transport_name, voice_media_info);
Henrik Boström883eefc2019-05-27 11:40:253250 return;
3251 }
3252 case cricket::MEDIA_TYPE_VIDEO: {
3253 cricket::VideoMediaInfo video_media_info;
Eldar Relloc07e9042020-07-03 08:08:073254 for (const auto& report_block_data : report_block_datas) {
3255 cricket::VideoSenderInfo sender;
3256 sender.local_stats.push_back(cricket::SsrcSenderInfo());
Danil Chapovalovd5b51672023-05-04 08:56:073257 sender.local_stats[0].ssrc = report_block_data.source_ssrc();
Eldar Relloc07e9042020-07-03 08:08:073258 if (codec.has_value()) {
3259 sender.codec_payload_type = codec->payload_type;
3260 video_media_info.send_codecs.insert(
3261 std::make_pair(codec->payload_type, *codec));
3262 }
3263 sender.report_block_datas.push_back(report_block_data);
3264 video_media_info.aggregated_senders.push_back(sender);
3265 video_media_info.senders.push_back(sender);
Henrik Boström883eefc2019-05-27 11:40:253266 }
Tommi19015512022-02-02 10:49:353267 pc_->AddVideoChannel("mid", transport_name, video_media_info);
Henrik Boström883eefc2019-05-27 11:40:253268 return;
3269 }
3270 case cricket::MEDIA_TYPE_DATA:
Philipp Hancke4e8c1152020-10-13 10:43:153271 case cricket::MEDIA_TYPE_UNSUPPORTED:
Artem Titovd3251962021-11-15 15:57:073272 RTC_DCHECK_NOTREACHED();
Henrik Boström883eefc2019-05-27 11:40:253273 }
3274 }
3275
3276 protected:
3277 cricket::MediaType media_type_;
3278};
3279
3280// Verifies RTCRemoteInboundRtpStreamStats members that don't require
3281// RTCCodecStats (codecId, jitter) and without setting up an RTCP transport.
3282TEST_P(RTCStatsCollectorTestWithParamKind,
3283 RTCRemoteInboundRtpStreamStatsCollectedFromReportBlock) {
Danil Chapovalovec2670e2023-04-12 11:11:213284 const Timestamp kReportBlockTimestampUtc = Timestamp::Micros(123456789);
Di Wu86f04ad2021-03-01 07:36:033285 const uint8_t kFractionLost = 12;
Danil Chapovalovec2670e2023-04-12 11:11:213286 const TimeDelta kRoundTripTimeSample1 = TimeDelta::Millis(1'234);
3287 const TimeDelta kRoundTripTimeSample2 = TimeDelta::Seconds(13);
Henrik Boström883eefc2019-05-27 11:40:253288
3289 // The report block's timestamp cannot be from the future, set the fake clock
3290 // to match.
Danil Chapovalovec2670e2023-04-12 11:11:213291 fake_clock_.SetTime(kReportBlockTimestampUtc);
Eldar Relloc07e9042020-07-03 08:08:073292 auto ssrcs = {12, 13};
3293 std::vector<ReportBlockData> report_block_datas;
3294 for (auto ssrc : ssrcs) {
Danil Chapovalovec2670e2023-04-12 11:11:213295 rtcp::ReportBlock report_block;
Eldar Relloc07e9042020-07-03 08:08:073296 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
Artem Titov880fa812021-07-30 20:30:233297 // `source_ssrc`, "SSRC of the RTP packet sender".
Danil Chapovalovec2670e2023-04-12 11:11:213298 report_block.SetMediaSsrc(ssrc);
3299 report_block.SetCumulativeLost(7);
3300 report_block.SetFractionLost(kFractionLost);
Eldar Relloc07e9042020-07-03 08:08:073301 ReportBlockData report_block_data;
Danil Chapovalovec2670e2023-04-12 11:11:213302 report_block_data.SetReportBlock(0, report_block, kReportBlockTimestampUtc);
3303 report_block_data.AddRoundTripTimeSample(kRoundTripTimeSample1);
Eldar Relloc07e9042020-07-03 08:08:073304 // Only the last sample should be exposed as the
Artem Titovcfea2182021-08-09 23:22:313305 // `RTCRemoteInboundRtpStreamStats::round_trip_time`.
Danil Chapovalovec2670e2023-04-12 11:11:213306 report_block_data.AddRoundTripTimeSample(kRoundTripTimeSample2);
Eldar Relloc07e9042020-07-03 08:08:073307 report_block_datas.push_back(report_block_data);
3308 }
3309 AddSenderInfoAndMediaChannel("TransportName", report_block_datas,
Henrik Boström883eefc2019-05-27 11:40:253310 absl::nullopt);
3311
3312 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Eldar Relloc07e9042020-07-03 08:08:073313 for (auto ssrc : ssrcs) {
Henrik Boström8dfc90f2022-09-02 07:39:293314 std::string stream_id = "" + std::to_string(ssrc);
Eldar Relloc07e9042020-07-03 08:08:073315 RTCRemoteInboundRtpStreamStats expected_remote_inbound_rtp(
Danil Chapovalovec2670e2023-04-12 11:11:213316 "RI" + MediaTypeCharStr() + stream_id, kReportBlockTimestampUtc);
Eldar Relloc07e9042020-07-03 08:08:073317 expected_remote_inbound_rtp.ssrc = ssrc;
Di Wu86f04ad2021-03-01 07:36:033318 expected_remote_inbound_rtp.fraction_lost =
3319 static_cast<double>(kFractionLost) / (1 << 8);
Henrik Boström8dfc90f2022-09-02 07:39:293320 expected_remote_inbound_rtp.kind = MediaTypeKind();
Eldar Relloc07e9042020-07-03 08:08:073321 expected_remote_inbound_rtp.transport_id =
Henrik Boström8dfc90f2022-09-02 07:39:293322 "TTransportName1"; // 1 for RTP (we have no RTCP
3323 // transport)
Eldar Relloc07e9042020-07-03 08:08:073324 expected_remote_inbound_rtp.packets_lost = 7;
Henrik Boströmb43e3bb2022-09-26 10:36:443325 expected_remote_inbound_rtp.local_id =
3326 "OTTransportName1" + MediaTypeCharStr() + stream_id;
Danil Chapovalovec2670e2023-04-12 11:11:213327 expected_remote_inbound_rtp.round_trip_time =
3328 kRoundTripTimeSample2.seconds<double>();
Di Wu88a51b22021-03-01 19:22:063329 expected_remote_inbound_rtp.total_round_trip_time =
Danil Chapovalovec2670e2023-04-12 11:11:213330 (kRoundTripTimeSample1 + kRoundTripTimeSample2).seconds<double>();
Di Wu88a51b22021-03-01 19:22:063331 expected_remote_inbound_rtp.round_trip_time_measurements = 2;
Artem Titov880fa812021-07-30 20:30:233332 // This test does not set up RTCCodecStats, so `codec_id` and `jitter` are
Eldar Relloc07e9042020-07-03 08:08:073333 // expected to be missing. These are tested separately.
Henrik Boström883eefc2019-05-27 11:40:253334
Eldar Relloc07e9042020-07-03 08:08:073335 ASSERT_TRUE(report->Get(expected_remote_inbound_rtp.id()));
3336 EXPECT_EQ(report->Get(expected_remote_inbound_rtp.id())
3337 ->cast_to<RTCRemoteInboundRtpStreamStats>(),
3338 expected_remote_inbound_rtp);
3339 EXPECT_TRUE(report->Get(*expected_remote_inbound_rtp.transport_id));
3340 ASSERT_TRUE(report->Get(*expected_remote_inbound_rtp.local_id));
3341 // Lookup works in both directions.
3342 EXPECT_EQ(*report->Get(*expected_remote_inbound_rtp.local_id)
Philipp Hancke1f98b462023-03-07 08:53:593343 ->cast_to<RTCOutboundRtpStreamStats>()
Eldar Relloc07e9042020-07-03 08:08:073344 .remote_id,
3345 expected_remote_inbound_rtp.id());
3346 }
Henrik Boström883eefc2019-05-27 11:40:253347}
3348
3349TEST_P(RTCStatsCollectorTestWithParamKind,
Henrik Boströma3a3b6d2022-11-22 08:56:493350 RTCRemoteInboundRtpStreamStatsRttMissingBeforeMeasurement) {
Danil Chapovalovec2670e2023-04-12 11:11:213351 constexpr Timestamp kReportBlockTimestampUtc = Timestamp::Micros(123456789);
Henrik Boströma3a3b6d2022-11-22 08:56:493352
Danil Chapovalovec2670e2023-04-12 11:11:213353 rtcp::ReportBlock report_block;
Henrik Boströma3a3b6d2022-11-22 08:56:493354 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
3355 // `source_ssrc`, "SSRC of the RTP packet sender".
Danil Chapovalovec2670e2023-04-12 11:11:213356 report_block.SetMediaSsrc(12);
Henrik Boströma3a3b6d2022-11-22 08:56:493357 ReportBlockData report_block_data; // AddRoundTripTimeSample() not called.
Danil Chapovalovec2670e2023-04-12 11:11:213358 report_block_data.SetReportBlock(0, report_block, kReportBlockTimestampUtc);
Henrik Boströma3a3b6d2022-11-22 08:56:493359
3360 AddSenderInfoAndMediaChannel("TransportName", {report_block_data},
3361 absl::nullopt);
3362
3363 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3364
3365 std::string remote_inbound_rtp_id = "RI" + MediaTypeCharStr() + "12";
3366 ASSERT_TRUE(report->Get(remote_inbound_rtp_id));
3367 auto& remote_inbound_rtp = report->Get(remote_inbound_rtp_id)
3368 ->cast_to<RTCRemoteInboundRtpStreamStats>();
3369
3370 EXPECT_TRUE(remote_inbound_rtp.round_trip_time_measurements.is_defined());
3371 EXPECT_EQ(0, *remote_inbound_rtp.round_trip_time_measurements);
3372 EXPECT_FALSE(remote_inbound_rtp.round_trip_time.is_defined());
3373}
3374
3375TEST_P(RTCStatsCollectorTestWithParamKind,
Henrik Boström883eefc2019-05-27 11:40:253376 RTCRemoteInboundRtpStreamStatsWithTimestampFromReportBlock) {
Danil Chapovalovec2670e2023-04-12 11:11:213377 const Timestamp kReportBlockTimestampUtc = Timestamp::Micros(123456789);
3378 fake_clock_.SetTime(kReportBlockTimestampUtc);
Henrik Boström883eefc2019-05-27 11:40:253379
Danil Chapovalovec2670e2023-04-12 11:11:213380 rtcp::ReportBlock report_block;
Henrik Boström8605fbf2019-06-24 14:44:513381 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
Artem Titov880fa812021-07-30 20:30:233382 // `source_ssrc`, "SSRC of the RTP packet sender".
Danil Chapovalovec2670e2023-04-12 11:11:213383 report_block.SetMediaSsrc(12);
Henrik Boström883eefc2019-05-27 11:40:253384 ReportBlockData report_block_data;
Danil Chapovalovec2670e2023-04-12 11:11:213385 report_block_data.SetReportBlock(0, report_block, kReportBlockTimestampUtc);
Henrik Boström883eefc2019-05-27 11:40:253386
Eldar Relloc07e9042020-07-03 08:08:073387 AddSenderInfoAndMediaChannel("TransportName", {report_block_data},
Henrik Boström883eefc2019-05-27 11:40:253388 absl::nullopt);
3389
3390 // Advance time, it should be OK to have fresher reports than report blocks.
Danil Chapovalov0c626af2020-02-10 10:16:003391 fake_clock_.AdvanceTime(TimeDelta::Micros(1234));
Henrik Boström883eefc2019-05-27 11:40:253392
3393 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3394
Henrik Boström8dfc90f2022-09-02 07:39:293395 std::string remote_inbound_rtp_id = "RI" + MediaTypeCharStr() + "12";
Henrik Boström883eefc2019-05-27 11:40:253396 ASSERT_TRUE(report->Get(remote_inbound_rtp_id));
3397 auto& remote_inbound_rtp = report->Get(remote_inbound_rtp_id)
3398 ->cast_to<RTCRemoteInboundRtpStreamStats>();
3399
3400 // Even though the report time is different, the remote-inbound-rtp timestamp
3401 // is of the time that the report block was received.
Danil Chapovalovec2670e2023-04-12 11:11:213402 EXPECT_EQ(report->timestamp(),
3403 kReportBlockTimestampUtc + TimeDelta::Micros(1234));
3404 EXPECT_EQ(remote_inbound_rtp.timestamp(), kReportBlockTimestampUtc);
Henrik Boström883eefc2019-05-27 11:40:253405}
3406
3407TEST_P(RTCStatsCollectorTestWithParamKind,
3408 RTCRemoteInboundRtpStreamStatsWithCodecBasedMembers) {
Danil Chapovalovec2670e2023-04-12 11:11:213409 const Timestamp kReportBlockTimestampUtc = Timestamp::Micros(123456789);
3410 fake_clock_.SetTime(kReportBlockTimestampUtc);
Henrik Boström883eefc2019-05-27 11:40:253411
Danil Chapovalovec2670e2023-04-12 11:11:213412 rtcp::ReportBlock report_block;
Henrik Boström8605fbf2019-06-24 14:44:513413 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
Artem Titov880fa812021-07-30 20:30:233414 // `source_ssrc`, "SSRC of the RTP packet sender".
Danil Chapovalovec2670e2023-04-12 11:11:213415 report_block.SetMediaSsrc(12);
3416 report_block.SetJitter(5000);
Henrik Boström883eefc2019-05-27 11:40:253417 ReportBlockData report_block_data;
Danil Chapovalovec2670e2023-04-12 11:11:213418 report_block_data.SetReportBlock(0, report_block, kReportBlockTimestampUtc);
Henrik Boström883eefc2019-05-27 11:40:253419
3420 RtpCodecParameters codec;
3421 codec.payload_type = 3;
3422 codec.kind = media_type_;
3423 codec.clock_rate = 1000;
3424
Eldar Relloc07e9042020-07-03 08:08:073425 AddSenderInfoAndMediaChannel("TransportName", {report_block_data}, codec);
Henrik Boström883eefc2019-05-27 11:40:253426
3427 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3428
Henrik Boström8dfc90f2022-09-02 07:39:293429 std::string remote_inbound_rtp_id = "RI" + MediaTypeCharStr() + "12";
Henrik Boström883eefc2019-05-27 11:40:253430 ASSERT_TRUE(report->Get(remote_inbound_rtp_id));
3431 auto& remote_inbound_rtp = report->Get(remote_inbound_rtp_id)
3432 ->cast_to<RTCRemoteInboundRtpStreamStats>();
3433
3434 EXPECT_TRUE(remote_inbound_rtp.codec_id.is_defined());
3435 EXPECT_TRUE(report->Get(*remote_inbound_rtp.codec_id));
3436
3437 EXPECT_TRUE(remote_inbound_rtp.jitter.is_defined());
3438 // The jitter (in seconds) is the report block's jitter divided by the codec's
3439 // clock rate.
3440 EXPECT_EQ(5.0, *remote_inbound_rtp.jitter);
3441}
3442
3443TEST_P(RTCStatsCollectorTestWithParamKind,
3444 RTCRemoteInboundRtpStreamStatsWithRtcpTransport) {
Danil Chapovalovec2670e2023-04-12 11:11:213445 const Timestamp kReportBlockTimestampUtc = Timestamp::Micros(123456789);
3446 fake_clock_.SetTime(kReportBlockTimestampUtc);
Henrik Boström883eefc2019-05-27 11:40:253447
Danil Chapovalovec2670e2023-04-12 11:11:213448 rtcp::ReportBlock report_block;
Henrik Boström8605fbf2019-06-24 14:44:513449 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
Artem Titov880fa812021-07-30 20:30:233450 // `source_ssrc`, "SSRC of the RTP packet sender".
Danil Chapovalovec2670e2023-04-12 11:11:213451 report_block.SetMediaSsrc(12);
Henrik Boström883eefc2019-05-27 11:40:253452 ReportBlockData report_block_data;
Danil Chapovalovec2670e2023-04-12 11:11:213453 report_block_data.SetReportBlock(0, report_block, kReportBlockTimestampUtc);
Henrik Boström883eefc2019-05-27 11:40:253454
3455 cricket::TransportChannelStats rtp_transport_channel_stats;
3456 rtp_transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
Mirko Bonadei9f6808b2021-05-21 18:46:093457 rtp_transport_channel_stats.dtls_state = DtlsTransportState::kNew;
Henrik Boström883eefc2019-05-27 11:40:253458 cricket::TransportChannelStats rtcp_transport_channel_stats;
3459 rtcp_transport_channel_stats.component =
3460 cricket::ICE_CANDIDATE_COMPONENT_RTCP;
Mirko Bonadei9f6808b2021-05-21 18:46:093461 rtcp_transport_channel_stats.dtls_state = DtlsTransportState::kNew;
Henrik Boström883eefc2019-05-27 11:40:253462 pc_->SetTransportStats("TransportName", {rtp_transport_channel_stats,
3463 rtcp_transport_channel_stats});
Eldar Relloc07e9042020-07-03 08:08:073464 AddSenderInfoAndMediaChannel("TransportName", {report_block_data},
Henrik Boström883eefc2019-05-27 11:40:253465 absl::nullopt);
3466
3467 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3468
Henrik Boström8dfc90f2022-09-02 07:39:293469 std::string remote_inbound_rtp_id = "RI" + MediaTypeCharStr() + "12";
Henrik Boström883eefc2019-05-27 11:40:253470 ASSERT_TRUE(report->Get(remote_inbound_rtp_id));
3471 auto& remote_inbound_rtp = report->Get(remote_inbound_rtp_id)
3472 ->cast_to<RTCRemoteInboundRtpStreamStats>();
3473
3474 EXPECT_TRUE(remote_inbound_rtp.transport_id.is_defined());
Henrik Boström8dfc90f2022-09-02 07:39:293475 EXPECT_EQ("TTransportName2", // 2 for RTCP
Henrik Boström883eefc2019-05-27 11:40:253476 *remote_inbound_rtp.transport_id);
3477 EXPECT_TRUE(report->Get(*remote_inbound_rtp.transport_id));
3478}
3479
Mirko Bonadei1b575412019-09-23 06:34:503480INSTANTIATE_TEST_SUITE_P(All,
Henrik Boström883eefc2019-05-27 11:40:253481 RTCStatsCollectorTestWithParamKind,
3482 ::testing::Values(cricket::MEDIA_TYPE_AUDIO, // "/0"
3483 cricket::MEDIA_TYPE_VIDEO)); // "/1"
3484
Alessio Bazzicaf7b1b952021-03-23 16:23:043485// Checks that no remote outbound stats are collected if not available in
3486// `VoiceMediaInfo`.
3487TEST_F(RTCStatsCollectorTest,
3488 RTCRemoteOutboundRtpAudioStreamStatsNotCollected) {
3489 ExampleStatsGraph graph =
3490 SetupExampleStatsVoiceGraph(/*add_remote_outbound_stats=*/false);
3491 EXPECT_FALSE(graph.full_report->Get(graph.remote_outbound_rtp_id));
3492 // Also check that no other remote outbound report is created (in case the
3493 // expected ID is incorrect).
3494 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3495 ASSERT_NE(report->begin(), report->end())
3496 << "No reports have been generated.";
3497 for (const auto& stats : *report) {
3498 SCOPED_TRACE(stats.id());
3499 EXPECT_NE(stats.type(), RTCRemoteOutboundRtpStreamStats::kType);
3500 }
3501}
3502
3503// Checks that the remote outbound stats are collected when available in
3504// `VoiceMediaInfo`.
3505TEST_F(RTCStatsCollectorTest, RTCRemoteOutboundRtpAudioStreamStatsCollected) {
3506 ExampleStatsGraph graph =
3507 SetupExampleStatsVoiceGraph(/*add_remote_outbound_stats=*/true);
3508 ASSERT_TRUE(graph.full_report->Get(graph.remote_outbound_rtp_id));
3509 const auto& remote_outbound_rtp =
3510 graph.full_report->Get(graph.remote_outbound_rtp_id)
3511 ->cast_to<RTCRemoteOutboundRtpStreamStats>();
Philipp Hanckeb81823a2023-01-04 14:17:423512 EXPECT_EQ(remote_outbound_rtp.timestamp(),
3513 Timestamp::Millis(kRemoteOutboundStatsTimestampMs));
Alessio Bazzicaf7b1b952021-03-23 16:23:043514 EXPECT_FLOAT_EQ(*remote_outbound_rtp.remote_timestamp,
3515 static_cast<double>(kRemoteOutboundStatsRemoteTimestampMs));
3516 EXPECT_EQ(*remote_outbound_rtp.packets_sent, kRemoteOutboundStatsPacketsSent);
3517 EXPECT_EQ(*remote_outbound_rtp.bytes_sent, kRemoteOutboundStatsBytesSent);
3518 EXPECT_EQ(*remote_outbound_rtp.reports_sent,
3519 kRemoteOutboundStatsReportsCount);
3520}
3521
Henrik Boström646fda02019-05-22 13:49:423522TEST_F(RTCStatsCollectorTest,
3523 RTCVideoSourceStatsNotCollectedForSenderWithoutTrack) {
3524 const uint32_t kSsrc = 4;
3525 const int kAttachmentId = 42;
3526
3527 cricket::VideoMediaInfo video_media_info;
3528 video_media_info.senders.push_back(cricket::VideoSenderInfo());
3529 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3530 video_media_info.senders[0].local_stats[0].ssrc = kSsrc;
Byoungchan Leeefe46b62021-11-10 02:23:563531 video_media_info.senders[0].framerate_input = 29.0;
Tommi19015512022-02-02 10:49:353532 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström646fda02019-05-22 13:49:423533
3534 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
3535 cricket::MEDIA_TYPE_VIDEO, /*track=*/nullptr, kSsrc, kAttachmentId, {});
Tommi6589def2022-02-17 22:36:473536 EXPECT_CALL(*sender, Stop());
3537 EXPECT_CALL(*sender, SetMediaChannel(_));
Henrik Boström646fda02019-05-22 13:49:423538 pc_->AddSender(sender);
3539
3540 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Henrik Boström8dfc90f2022-09-02 07:39:293541 EXPECT_FALSE(report->Get("SV42"));
Henrik Boström646fda02019-05-22 13:49:423542}
3543
Taylor Brandstetter64851c02021-06-24 20:32:503544// Test collecting echo return loss stats from the audio processor attached to
3545// the track, rather than the voice sender info.
3546TEST_F(RTCStatsCollectorTest, CollectEchoReturnLossFromTrackAudioProcessor) {
3547 rtc::scoped_refptr<MediaStream> local_stream =
3548 MediaStream::Create("LocalStreamId");
3549 pc_->mutable_local_streams()->AddStream(local_stream);
3550
3551 // Local audio track
3552 rtc::scoped_refptr<MediaStreamTrackInterface> local_audio_track =
3553 CreateFakeTrack(cricket::MEDIA_TYPE_AUDIO, "LocalAudioTrackID",
3554 MediaStreamTrackInterface::kEnded,
3555 /*create_fake_audio_processor=*/true);
Harald Alvestrand2f7ad282022-04-21 11:35:433556 local_stream->AddTrack(rtc::scoped_refptr<AudioTrackInterface>(
3557 static_cast<AudioTrackInterface*>(local_audio_track.get())));
Taylor Brandstetter64851c02021-06-24 20:32:503558
3559 cricket::VoiceSenderInfo voice_sender_info_ssrc1;
3560 voice_sender_info_ssrc1.local_stats.push_back(cricket::SsrcSenderInfo());
3561 voice_sender_info_ssrc1.local_stats[0].ssrc = 1;
3562
3563 stats_->CreateMockRtpSendersReceiversAndChannels(
3564 {std::make_pair(local_audio_track.get(), voice_sender_info_ssrc1)}, {},
3565 {}, {}, {local_stream->id()}, {});
3566
3567 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3568
Philipp Hanckeb81823a2023-01-04 14:17:423569 RTCAudioSourceStats expected_audio("SA11", report->timestamp());
Taylor Brandstetter64851c02021-06-24 20:32:503570 expected_audio.track_identifier = "LocalAudioTrackID";
3571 expected_audio.kind = "audio";
3572 expected_audio.audio_level = 0;
3573 expected_audio.total_audio_energy = 0;
3574 expected_audio.total_samples_duration = 0;
3575 expected_audio.echo_return_loss = 2.0;
3576 expected_audio.echo_return_loss_enhancement = 3.0;
3577
3578 ASSERT_TRUE(report->Get(expected_audio.id()));
3579 EXPECT_EQ(report->Get(expected_audio.id())->cast_to<RTCAudioSourceStats>(),
3580 expected_audio);
3581}
3582
Henrik Boström5b3541f2018-03-19 12:52:563583TEST_F(RTCStatsCollectorTest, GetStatsWithSenderSelector) {
3584 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
3585 // Expected stats graph when filtered by sender:
3586 //
Henrik Boström646fda02019-05-22 13:49:423587 // media-source
Henrik Boström4e231ee2023-05-24 09:24:133588 // ^
3589 // |
3590 // +--------- outbound-rtp
3591 // | |
3592 // v v
3593 // codec (send) transport
Henrik Boström5b3541f2018-03-19 12:52:563594 rtc::scoped_refptr<const RTCStatsReport> sender_report =
3595 stats_->GetStatsReportWithSenderSelector(graph.sender);
3596 EXPECT_TRUE(sender_report);
Philipp Hanckeb81823a2023-01-04 14:17:423597 EXPECT_EQ(sender_report->timestamp(), graph.full_report->timestamp());
Henrik Boström4e231ee2023-05-24 09:24:133598 EXPECT_EQ(sender_report->size(), 4u);
Henrik Boström5b3541f2018-03-19 12:52:563599 EXPECT_TRUE(sender_report->Get(graph.send_codec_id));
3600 EXPECT_FALSE(sender_report->Get(graph.recv_codec_id));
3601 EXPECT_TRUE(sender_report->Get(graph.outbound_rtp_id));
3602 EXPECT_FALSE(sender_report->Get(graph.inbound_rtp_id));
3603 EXPECT_TRUE(sender_report->Get(graph.transport_id));
Henrik Boström5b3541f2018-03-19 12:52:563604 EXPECT_FALSE(sender_report->Get(graph.peer_connection_id));
Henrik Boström646fda02019-05-22 13:49:423605 EXPECT_TRUE(sender_report->Get(graph.media_source_id));
Henrik Boström5b3541f2018-03-19 12:52:563606}
3607
3608TEST_F(RTCStatsCollectorTest, GetStatsWithReceiverSelector) {
3609 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
3610 // Expected stats graph when filtered by receiver:
3611 //
Henrik Boström4e231ee2023-05-24 09:24:133612 //
3613 //
3614 // inbound-rtp
Henrik Boström646fda02019-05-22 13:49:423615 // | |
3616 // v v
3617 // transport codec (recv)
Henrik Boström5b3541f2018-03-19 12:52:563618 rtc::scoped_refptr<const RTCStatsReport> receiver_report =
3619 stats_->GetStatsReportWithReceiverSelector(graph.receiver);
3620 EXPECT_TRUE(receiver_report);
Henrik Boström4e231ee2023-05-24 09:24:133621 EXPECT_EQ(receiver_report->size(), 3u);
Philipp Hanckeb81823a2023-01-04 14:17:423622 EXPECT_EQ(receiver_report->timestamp(), graph.full_report->timestamp());
Henrik Boström5b3541f2018-03-19 12:52:563623 EXPECT_FALSE(receiver_report->Get(graph.send_codec_id));
3624 EXPECT_TRUE(receiver_report->Get(graph.recv_codec_id));
3625 EXPECT_FALSE(receiver_report->Get(graph.outbound_rtp_id));
3626 EXPECT_TRUE(receiver_report->Get(graph.inbound_rtp_id));
3627 EXPECT_TRUE(receiver_report->Get(graph.transport_id));
Henrik Boström5b3541f2018-03-19 12:52:563628 EXPECT_FALSE(receiver_report->Get(graph.peer_connection_id));
Henrik Boström646fda02019-05-22 13:49:423629 EXPECT_FALSE(receiver_report->Get(graph.media_source_id));
Henrik Boström5b3541f2018-03-19 12:52:563630}
3631
3632TEST_F(RTCStatsCollectorTest, GetStatsWithNullSenderSelector) {
3633 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
3634 rtc::scoped_refptr<const RTCStatsReport> empty_report =
3635 stats_->GetStatsReportWithSenderSelector(nullptr);
3636 EXPECT_TRUE(empty_report);
Philipp Hanckeb81823a2023-01-04 14:17:423637 EXPECT_EQ(empty_report->timestamp(), graph.full_report->timestamp());
Henrik Boström5b3541f2018-03-19 12:52:563638 EXPECT_EQ(empty_report->size(), 0u);
3639}
3640
3641TEST_F(RTCStatsCollectorTest, GetStatsWithNullReceiverSelector) {
3642 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
3643 rtc::scoped_refptr<const RTCStatsReport> empty_report =
3644 stats_->GetStatsReportWithReceiverSelector(nullptr);
3645 EXPECT_TRUE(empty_report);
Philipp Hanckeb81823a2023-01-04 14:17:423646 EXPECT_EQ(empty_report->timestamp(), graph.full_report->timestamp());
Henrik Boström5b3541f2018-03-19 12:52:563647 EXPECT_EQ(empty_report->size(), 0u);
3648}
3649
Henrik Boström5ed4da72022-12-24 10:20:123650// Before SetLocalDescription() senders don't have an SSRC.
3651// To simulate this case we create a mock sender with SSRC=0.
3652TEST_F(RTCStatsCollectorTest, RtpIsMissingWhileSsrcIsZero) {
Harald Alvestrand89061872018-01-02 13:08:343653 rtc::scoped_refptr<MediaStreamTrackInterface> track =
3654 CreateFakeTrack(cricket::MEDIA_TYPE_AUDIO, "audioTrack",
3655 MediaStreamTrackInterface::kLive);
Steve Anton57858b32018-02-15 23:19:503656 rtc::scoped_refptr<MockRtpSenderInternal> sender =
Henrik Boström646fda02019-05-22 13:49:423657 CreateMockSender(cricket::MEDIA_TYPE_AUDIO, track, 0, 49, {});
Tommi6589def2022-02-17 22:36:473658 EXPECT_CALL(*sender, Stop());
Steve Anton5b387312018-02-03 00:00:203659 pc_->AddSender(sender);
3660
3661 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3662
Philipp Hancke1f98b462023-03-07 08:53:593663 auto outbound_rtps = report->GetStatsOfType<RTCOutboundRtpStreamStats>();
Henrik Boström5ed4da72022-12-24 10:20:123664 EXPECT_TRUE(outbound_rtps.empty());
Harald Alvestrand89061872018-01-02 13:08:343665}
3666
Henrik Boström5ed4da72022-12-24 10:20:123667// We may also be in a case where the SSRC has been assigned but no
3668// `voice_sender_info` stats exist yet.
3669TEST_F(RTCStatsCollectorTest, DoNotCrashIfSsrcIsKnownButInfosAreStillMissing) {
Harald Alvestrand76d29522018-01-30 13:43:293670 rtc::scoped_refptr<MediaStreamTrackInterface> track =
3671 CreateFakeTrack(cricket::MEDIA_TYPE_AUDIO, "audioTrack",
3672 MediaStreamTrackInterface::kLive);
Steve Anton57858b32018-02-15 23:19:503673 rtc::scoped_refptr<MockRtpSenderInternal> sender =
Henrik Boström646fda02019-05-22 13:49:423674 CreateMockSender(cricket::MEDIA_TYPE_AUDIO, track, 4711, 49, {});
Tommi6589def2022-02-17 22:36:473675 EXPECT_CALL(*sender, Stop());
Steve Anton5b387312018-02-03 00:00:203676 pc_->AddSender(sender);
3677
Harald Alvestrand76d29522018-01-30 13:43:293678 // We do not generate any matching voice_sender_info stats.
Steve Anton5b387312018-02-03 00:00:203679 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3680
Philipp Hancke1f98b462023-03-07 08:53:593681 auto outbound_rtps = report->GetStatsOfType<RTCOutboundRtpStreamStats>();
Henrik Boström5ed4da72022-12-24 10:20:123682 EXPECT_TRUE(outbound_rtps.empty());
Harald Alvestrand76d29522018-01-30 13:43:293683}
3684
Taylor Brandstetter87d5a742018-03-06 17:42:253685// Used for test below, to test calling GetStatsReport during a callback.
Taylor Brandstetter25e022f2018-03-08 17:53:473686class RecursiveCallback : public RTCStatsCollectorCallback {
Taylor Brandstetter87d5a742018-03-06 17:42:253687 public:
Taylor Brandstetter25e022f2018-03-08 17:53:473688 explicit RecursiveCallback(RTCStatsCollectorWrapper* stats) : stats_(stats) {}
Taylor Brandstetter87d5a742018-03-06 17:42:253689
3690 void OnStatsDelivered(
3691 const rtc::scoped_refptr<const RTCStatsReport>& report) override {
3692 stats_->GetStatsReport();
3693 called_ = true;
3694 }
3695
3696 bool called() const { return called_; }
3697
3698 private:
3699 RTCStatsCollectorWrapper* stats_;
3700 bool called_ = false;
3701};
3702
3703// Test that nothing bad happens if a callback causes GetStatsReport to be
3704// called again recursively. Regression test for crbug.com/webrtc/8973.
Taylor Brandstetter25e022f2018-03-08 17:53:473705TEST_F(RTCStatsCollectorTest, DoNotCrashWhenGetStatsCalledDuringCallback) {
Niels Möller027c7932022-01-25 12:56:073706 auto callback1 = rtc::make_ref_counted<RecursiveCallback>(stats_.get());
3707 auto callback2 = rtc::make_ref_counted<RecursiveCallback>(stats_.get());
Taylor Brandstetter87d5a742018-03-06 17:42:253708 stats_->stats_collector()->GetStatsReport(callback1);
3709 stats_->stats_collector()->GetStatsReport(callback2);
3710 EXPECT_TRUE_WAIT(callback1->called(), kGetStatsReportTimeoutMs);
3711 EXPECT_TRUE_WAIT(callback2->called(), kGetStatsReportTimeoutMs);
3712}
3713
Steve Anton5b387312018-02-03 00:00:203714class RTCTestStats : public RTCStats {
hbosc82f2e12016-09-05 08:36:503715 public:
Steve Anton5b387312018-02-03 00:00:203716 WEBRTC_RTCSTATS_DECL();
3717
Philipp Hanckeb81823a2023-01-04 14:17:423718 RTCTestStats(const std::string& id, Timestamp timestamp)
3719 : RTCStats(id, timestamp), dummy_stat("dummyStat") {}
Steve Anton5b387312018-02-03 00:00:203720
3721 RTCStatsMember<int32_t> dummy_stat;
3722};
3723
Mirko Bonadeic4dd7302019-02-25 08:12:023724WEBRTC_RTCSTATS_IMPL(RTCTestStats, RTCStats, "test-stats", &dummy_stat)
Steve Anton5b387312018-02-03 00:00:203725
3726// Overrides the stats collection to verify thread usage and that the resulting
3727// partial reports are merged.
3728class FakeRTCStatsCollector : public RTCStatsCollector,
3729 public RTCStatsCollectorCallback {
3730 public:
3731 static rtc::scoped_refptr<FakeRTCStatsCollector> Create(
3732 PeerConnectionInternal* pc,
3733 int64_t cache_lifetime_us) {
Niels Möllere7cc8832022-01-04 14:20:033734 return rtc::scoped_refptr<FakeRTCStatsCollector>(
3735 new rtc::RefCountedObject<FakeRTCStatsCollector>(pc,
3736 cache_lifetime_us));
Steve Anton5b387312018-02-03 00:00:203737 }
3738
Tomas Gunnarssone6de5ae2021-04-22 16:16:353739 // Since FakeRTCStatsCollector inherits twice from RefCountInterface, once via
3740 // RTCStatsCollector and once via RTCStatsCollectorCallback, scoped_refptr
3741 // will get confused about which AddRef()/Release() methods to call.
3742 // So to remove all doubt, we declare them here again in the class that we
3743 // give to scoped_refptr.
3744 // Satisfying the implementation of these methods and associating them with a
3745 // reference counter, will be done by RefCountedObject.
3746 virtual void AddRef() const = 0;
3747 virtual rtc::RefCountReleaseStatus Release() const = 0;
3748
Steve Anton5b387312018-02-03 00:00:203749 // RTCStatsCollectorCallback implementation.
3750 void OnStatsDelivered(
3751 const rtc::scoped_refptr<const RTCStatsReport>& report) override {
3752 EXPECT_TRUE(signaling_thread_->IsCurrent());
Markus Handell6fcd0f82020-07-07 17:08:533753 MutexLock lock(&lock_);
Steve Anton5b387312018-02-03 00:00:203754 delivered_report_ = report;
3755 }
3756
3757 void VerifyThreadUsageAndResultsMerging() {
3758 GetStatsReport(rtc::scoped_refptr<RTCStatsCollectorCallback>(this));
3759 EXPECT_TRUE_WAIT(HasVerifiedResults(), kGetStatsReportTimeoutMs);
3760 }
3761
3762 bool HasVerifiedResults() {
3763 EXPECT_TRUE(signaling_thread_->IsCurrent());
Markus Handell6fcd0f82020-07-07 17:08:533764 MutexLock lock(&lock_);
Steve Anton5b387312018-02-03 00:00:203765 if (!delivered_report_)
3766 return false;
3767 EXPECT_EQ(produced_on_signaling_thread_, 1);
3768 EXPECT_EQ(produced_on_network_thread_, 1);
3769
3770 EXPECT_TRUE(delivered_report_->Get("SignalingThreadStats"));
3771 EXPECT_TRUE(delivered_report_->Get("NetworkThreadStats"));
3772
3773 produced_on_signaling_thread_ = 0;
3774 produced_on_network_thread_ = 0;
3775 delivered_report_ = nullptr;
3776 return true;
hbosc82f2e12016-09-05 08:36:503777 }
3778
3779 protected:
Steve Anton5b387312018-02-03 00:00:203780 FakeRTCStatsCollector(PeerConnectionInternal* pc, int64_t cache_lifetime)
3781 : RTCStatsCollector(pc, cache_lifetime),
3782 signaling_thread_(pc->signaling_thread()),
3783 worker_thread_(pc->worker_thread()),
3784 network_thread_(pc->network_thread()) {}
3785
Henrik Boström40b030e2019-02-28 08:49:313786 void ProducePartialResultsOnSignalingThreadImpl(
Philipp Hanckeb81823a2023-01-04 14:17:423787 Timestamp timestamp,
Henrik Boström40b030e2019-02-28 08:49:313788 RTCStatsReport* partial_report) override {
Steve Anton5b387312018-02-03 00:00:203789 EXPECT_TRUE(signaling_thread_->IsCurrent());
3790 {
Markus Handell6fcd0f82020-07-07 17:08:533791 MutexLock lock(&lock_);
Steve Anton5b387312018-02-03 00:00:203792 EXPECT_FALSE(delivered_report_);
3793 ++produced_on_signaling_thread_;
3794 }
3795
Henrik Boström40b030e2019-02-28 08:49:313796 partial_report->AddStats(std::unique_ptr<const RTCStats>(
Philipp Hanckeb81823a2023-01-04 14:17:423797 new RTCTestStats("SignalingThreadStats", timestamp)));
Steve Anton5b387312018-02-03 00:00:203798 }
Henrik Boström40b030e2019-02-28 08:49:313799 void ProducePartialResultsOnNetworkThreadImpl(
Philipp Hanckeb81823a2023-01-04 14:17:423800 Timestamp timestamp,
Henrik Boström40b030e2019-02-28 08:49:313801 const std::map<std::string, cricket::TransportStats>&
3802 transport_stats_by_name,
3803 const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
3804 RTCStatsReport* partial_report) override {
Steve Anton5b387312018-02-03 00:00:203805 EXPECT_TRUE(network_thread_->IsCurrent());
3806 {
Markus Handell6fcd0f82020-07-07 17:08:533807 MutexLock lock(&lock_);
Steve Anton5b387312018-02-03 00:00:203808 EXPECT_FALSE(delivered_report_);
3809 ++produced_on_network_thread_;
3810 }
3811
Henrik Boström40b030e2019-02-28 08:49:313812 partial_report->AddStats(std::unique_ptr<const RTCStats>(
Philipp Hanckeb81823a2023-01-04 14:17:423813 new RTCTestStats("NetworkThreadStats", timestamp)));
Steve Anton5b387312018-02-03 00:00:203814 }
3815
3816 private:
3817 rtc::Thread* const signaling_thread_;
3818 rtc::Thread* const worker_thread_;
3819 rtc::Thread* const network_thread_;
3820
Markus Handell6fcd0f82020-07-07 17:08:533821 Mutex lock_;
Steve Anton5b387312018-02-03 00:00:203822 rtc::scoped_refptr<const RTCStatsReport> delivered_report_;
3823 int produced_on_signaling_thread_ = 0;
3824 int produced_on_network_thread_ = 0;
hbosc82f2e12016-09-05 08:36:503825};
3826
Steve Anton5b387312018-02-03 00:00:203827TEST(RTCStatsCollectorTestWithFakeCollector, ThreadUsageAndResultsMerging) {
Niels Möller83830f32022-05-20 07:12:573828 rtc::AutoThread main_thread_;
Niels Möller027c7932022-01-25 12:56:073829 auto pc = rtc::make_ref_counted<FakePeerConnectionForStats>();
Steve Anton5b387312018-02-03 00:00:203830 rtc::scoped_refptr<FakeRTCStatsCollector> stats_collector(
Niels Möllerafb246b2022-04-20 12:26:503831 FakeRTCStatsCollector::Create(pc.get(),
3832 50 * rtc::kNumMicrosecsPerMillisec));
Steve Anton5b387312018-02-03 00:00:203833 stats_collector->VerifyThreadUsageAndResultsMerging();
hbosc82f2e12016-09-05 08:36:503834}
3835
3836} // namespace
3837
hbosd565b732016-08-30 21:04:353838} // namespace webrtc