blob: 61b3bca1db2aae1602f9c0151e636e9432cfa363 [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"
Henrik Boström7978cf12024-01-11 10:41:1032#include "api/stats/attribute.h"
Harald Alvestrandc24a2182022-02-23 13:44:5933#include "api/stats/rtc_stats.h"
Steve Anton10542f22019-01-11 17:11:0034#include "api/stats/rtc_stats_report.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3135#include "api/stats/rtcstats_objects.h"
Sebastian Jansson5f83cf02018-05-08 12:52:2236#include "api/units/time_delta.h"
Harald Alvestrandc24a2182022-02-23 13:44:5937#include "api/units/timestamp.h"
38#include "api/video/recordable_encoded_frame.h"
39#include "api/video/video_content_type.h"
40#include "api/video/video_frame.h"
41#include "api/video/video_sink_interface.h"
42#include "api/video/video_source_interface.h"
Henrik Boströmc5f8f802022-10-19 15:50:0943#include "api/video/video_timing.h"
Evan Shrubsole9b235cd2022-12-06 10:09:1044#include "api/video_codecs/scalability_mode.h"
Harald Alvestrandc24a2182022-02-23 13:44:5945#include "common_video/include/quality_limitation_reason.h"
46#include "media/base/media_channel.h"
Fredrik Hernqvistefbe7532023-01-13 15:42:3647#include "modules/audio_device/include/audio_device.h"
Harald Alvestrandc24a2182022-02-23 13:44:5948#include "modules/audio_processing/include/audio_processing_statistics.h"
Henrik Boström883eefc2019-05-27 11:40:2549#include "modules/rtp_rtcp/include/report_block_data.h"
50#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
Harald Alvestrandc24a2182022-02-23 13:44:5951#include "p2p/base/connection_info.h"
52#include "p2p/base/ice_transport_internal.h"
Steve Anton10542f22019-01-11 17:11:0053#include "p2p/base/p2p_constants.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3154#include "p2p/base/port.h"
Steve Anton10542f22019-01-11 17:11:0055#include "pc/media_stream.h"
Harald Alvestrandc24a2182022-02-23 13:44:5956#include "pc/stream_collection.h"
Harald Alvestrand9e5aeb92022-05-11 09:35:3657#include "pc/test/fake_data_channel_controller.h"
Steve Anton10542f22019-01-11 17:11:0058#include "pc/test/fake_peer_connection_for_stats.h"
59#include "pc/test/mock_data_channel.h"
60#include "pc/test/mock_rtp_receiver_internal.h"
61#include "pc/test/mock_rtp_sender_internal.h"
62#include "pc/test/rtc_stats_obtainer.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3163#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 17:11:0064#include "rtc_base/fake_clock.h"
65#include "rtc_base/fake_ssl_identity.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3166#include "rtc_base/gunit.h"
Harald Alvestrandc24a2182022-02-23 13:44:5967#include "rtc_base/network_constants.h"
68#include "rtc_base/ref_counted_object.h"
69#include "rtc_base/rtc_certificate.h"
70#include "rtc_base/socket_address.h"
71#include "rtc_base/ssl_fingerprint.h"
72#include "rtc_base/ssl_identity.h"
73#include "rtc_base/ssl_stream_adapter.h"
74#include "rtc_base/string_encode.h"
Harald Alvestrand910cdc22020-01-09 11:58:2375#include "rtc_base/strings/json.h"
Markus Handell6fcd0f82020-07-07 17:08:5376#include "rtc_base/synchronization/mutex.h"
Steve Anton10542f22019-01-11 17:11:0077#include "rtc_base/time_utils.h"
Harald Alvestrandc24a2182022-02-23 13:44:5978#include "test/gmock.h"
79#include "test/gtest.h"
hbosd565b732016-08-30 21:04:3580
Alessio Bazzica049e6112021-03-18 11:55:1181using ::testing::_;
Mirko Bonadei6a489f22019-04-09 13:11:1282using ::testing::AtLeast;
83using ::testing::Invoke;
84using ::testing::Return;
hbosd565b732016-08-30 21:04:3585
86namespace webrtc {
87
Artem Titov880fa812021-07-30 20:30:2388// These are used by gtest code, such as if `EXPECT_EQ` fails.
hbosda389e32016-10-25 17:55:0889void PrintTo(const RTCCertificateStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:1290 *os << stats.ToJson();
hbosda389e32016-10-25 17:55:0891}
92
hbos0adb8282016-11-23 10:32:0693void PrintTo(const RTCCodecStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:1294 *os << stats.ToJson();
hbos0adb8282016-11-23 10:32:0695}
96
hbosda389e32016-10-25 17:55:0897void PrintTo(const RTCDataChannelStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:1298 *os << stats.ToJson();
hbosda389e32016-10-25 17:55:0899}
100
101void PrintTo(const RTCIceCandidatePairStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:12102 *os << stats.ToJson();
hbosda389e32016-10-25 17:55:08103}
104
105void PrintTo(const RTCLocalIceCandidateStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:12106 *os << stats.ToJson();
hbosda389e32016-10-25 17:55:08107}
108
109void PrintTo(const RTCRemoteIceCandidateStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:12110 *os << stats.ToJson();
hbosda389e32016-10-25 17:55:08111}
112
113void PrintTo(const RTCPeerConnectionStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:12114 *os << stats.ToJson();
hbosda389e32016-10-25 17:55:08115}
116
Philipp Hancke1f98b462023-03-07 08:53:59117void PrintTo(const RTCInboundRtpStreamStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:12118 *os << stats.ToJson();
hboseeafe942016-11-01 10:00:17119}
120
Philipp Hancke1f98b462023-03-07 08:53:59121void PrintTo(const RTCOutboundRtpStreamStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:12122 *os << stats.ToJson();
hbos6ded1902016-11-01 08:50:46123}
124
Henrik Boström883eefc2019-05-27 11:40:25125void PrintTo(const RTCRemoteInboundRtpStreamStats& stats, ::std::ostream* os) {
126 *os << stats.ToJson();
127}
128
Henrik Boström646fda02019-05-22 13:49:42129void PrintTo(const RTCAudioSourceStats& stats, ::std::ostream* os) {
130 *os << stats.ToJson();
131}
132
133void PrintTo(const RTCVideoSourceStats& stats, ::std::ostream* os) {
134 *os << stats.ToJson();
135}
136
hbosda389e32016-10-25 17:55:08137void PrintTo(const RTCTransportStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:12138 *os << stats.ToJson();
hbosda389e32016-10-25 17:55:08139}
140
hbosc82f2e12016-09-05 08:36:50141namespace {
142
143const int64_t kGetStatsReportTimeoutMs = 1000;
144
Alessio Bazzicaf7b1b952021-03-23 16:23:04145// Fake data used by `SetupExampleStatsVoiceGraph()` to fill in remote outbound
146// stats.
147constexpr int64_t kRemoteOutboundStatsTimestampMs = 123;
148constexpr int64_t kRemoteOutboundStatsRemoteTimestampMs = 456;
149constexpr uint32_t kRemoteOutboundStatsPacketsSent = 7u;
150constexpr uint64_t kRemoteOutboundStatsBytesSent = 8u;
151constexpr uint64_t kRemoteOutboundStatsReportsCount = 9u;
152
hbos6ab97ce02016-10-03 21:16:56153struct CertificateInfo {
154 rtc::scoped_refptr<rtc::RTCCertificate> certificate;
155 std::vector<std::string> ders;
156 std::vector<std::string> pems;
157 std::vector<std::string> fingerprints;
158};
159
Harald Alvestranda3dab842018-01-14 08:18:58160// Return the ID for an object of the given type in a report.
161// The object must be present and be unique.
162template <typename T>
163std::string IdForType(const RTCStatsReport* report) {
164 auto stats_of_my_type = report->RTCStatsReport::GetStatsOfType<T>();
165 // We cannot use ASSERT here, since we're within a function.
Mirko Bonadeie12c1fe2018-07-03 10:53:23166 EXPECT_EQ(1U, stats_of_my_type.size())
Harald Alvestranda3dab842018-01-14 08:18:58167 << "Unexpected number of stats of this type";
168 if (stats_of_my_type.size() == 1) {
169 return stats_of_my_type[0]->id();
170 } else {
171 // Return something that is not going to be a valid stas ID.
172 return "Type not found";
173 }
174}
175
hbos6ab97ce02016-10-03 21:16:56176std::unique_ptr<CertificateInfo> CreateFakeCertificateAndInfoFromDers(
177 const std::vector<std::string>& ders) {
178 RTC_CHECK(!ders.empty());
179 std::unique_ptr<CertificateInfo> info(new CertificateInfo());
180 info->ders = ders;
181 for (const std::string& der : ders) {
182 info->pems.push_back(rtc::SSLIdentity::DerToPem(
Yves Gerey665174f2018-06-19 13:03:05183 "CERTIFICATE", reinterpret_cast<const unsigned char*>(der.c_str()),
hbos6ab97ce02016-10-03 21:16:56184 der.length()));
185 }
186 info->certificate =
187 rtc::RTCCertificate::Create(std::unique_ptr<rtc::FakeSSLIdentity>(
Taylor Brandstetterc3928662018-02-23 21:04:51188 new rtc::FakeSSLIdentity(info->pems)));
hbos6ab97ce02016-10-03 21:16:56189 // Strip header/footer and newline characters of PEM strings.
190 for (size_t i = 0; i < info->pems.size(); ++i) {
Steve Anton1c9c9fc2019-02-14 23:13:09191 absl::StrReplaceAll({{"-----BEGIN CERTIFICATE-----", ""},
192 {"-----END CERTIFICATE-----", ""},
193 {"\n", ""}},
194 &info->pems[i]);
hbos6ab97ce02016-10-03 21:16:56195 }
Taylor Brandstetterc3928662018-02-23 21:04:51196 // Fingerprints for the whole certificate chain, starting with leaf
197 // certificate.
Benjamin Wright6c6c9df2018-10-25 08:16:26198 const rtc::SSLCertChain& chain = info->certificate->GetSSLCertificateChain();
Taylor Brandstetterc3928662018-02-23 21:04:51199 std::unique_ptr<rtc::SSLFingerprint> fp;
200 for (size_t i = 0; i < chain.GetSize(); i++) {
Steve Anton4905edb2018-10-16 02:27:44201 fp = rtc::SSLFingerprint::Create("sha-1", chain.Get(i));
Taylor Brandstetterc3928662018-02-23 21:04:51202 EXPECT_TRUE(fp);
203 info->fingerprints.push_back(fp->GetRfc4572Fingerprint());
hbos6ab97ce02016-10-03 21:16:56204 }
205 EXPECT_EQ(info->ders.size(), info->fingerprints.size());
206 return info;
207}
208
hbosab9f6e42016-10-07 09:18:47209std::unique_ptr<cricket::Candidate> CreateFakeCandidate(
210 const std::string& hostname,
211 int port,
212 const std::string& protocol,
Gary Liu37e489c2017-11-21 18:49:36213 const rtc::AdapterType adapter_type,
hbosab9f6e42016-10-07 09:18:47214 const std::string& candidate_type,
Jonas Oreland0d13bbd2022-03-02 10:17:36215 uint32_t priority,
216 const rtc::AdapterType underlying_type_for_vpn =
217 rtc::ADAPTER_TYPE_UNKNOWN) {
hbosab9f6e42016-10-07 09:18:47218 std::unique_ptr<cricket::Candidate> candidate(new cricket::Candidate());
219 candidate->set_address(rtc::SocketAddress(hostname, port));
220 candidate->set_protocol(protocol);
Gary Liu37e489c2017-11-21 18:49:36221 candidate->set_network_type(adapter_type);
Jonas Oreland0d13bbd2022-03-02 10:17:36222 candidate->set_underlying_type_for_vpn(underlying_type_for_vpn);
hbosab9f6e42016-10-07 09:18:47223 candidate->set_type(candidate_type);
224 candidate->set_priority(priority);
Philipp Hancke0e3cd632022-09-27 08:23:09225 // Defaults for testing.
226 candidate->set_foundation("foundationIsAString");
227 candidate->set_username("iceusernamefragment");
hbosab9f6e42016-10-07 09:18:47228 return candidate;
229}
230
Taylor Brandstetter64851c02021-06-24 20:32:50231class FakeAudioProcessor : public AudioProcessorInterface {
232 public:
233 FakeAudioProcessor() {}
234 ~FakeAudioProcessor() {}
235
236 private:
237 AudioProcessorInterface::AudioProcessorStatistics GetStats(
238 bool has_recv_streams) override {
239 AudioProcessorStatistics stats;
240 stats.apm_statistics.echo_return_loss = 2.0;
241 stats.apm_statistics.echo_return_loss_enhancement = 3.0;
242 return stats;
243 }
244};
245
Yves Gerey665174f2018-06-19 13:03:05246class FakeAudioTrackForStats : public MediaStreamTrack<AudioTrackInterface> {
hbos09bc1282016-11-08 14:29:22247 public:
248 static rtc::scoped_refptr<FakeAudioTrackForStats> Create(
249 const std::string& id,
Taylor Brandstetter64851c02021-06-24 20:32:50250 MediaStreamTrackInterface::TrackState state,
251 bool create_fake_audio_processor) {
Niels Möller027c7932022-01-25 12:56:07252 auto audio_track_stats = rtc::make_ref_counted<FakeAudioTrackForStats>(id);
hbos09bc1282016-11-08 14:29:22253 audio_track_stats->set_state(state);
Taylor Brandstetter64851c02021-06-24 20:32:50254 if (create_fake_audio_processor) {
255 audio_track_stats->processor_ =
256 rtc::make_ref_counted<FakeAudioProcessor>();
257 }
hbos09bc1282016-11-08 14:29:22258 return audio_track_stats;
259 }
260
Steve Anton36b29d12017-10-30 16:57:42261 explicit FakeAudioTrackForStats(const std::string& id)
262 : MediaStreamTrack<AudioTrackInterface>(id) {}
hbos09bc1282016-11-08 14:29:22263
264 std::string kind() const override {
265 return MediaStreamTrackInterface::kAudioKind;
266 }
Harald Alvestranda6544372023-11-13 09:33:56267 AudioSourceInterface* GetSource() const override { return nullptr; }
268 void AddSink(AudioTrackSinkInterface* sink) override {}
269 void RemoveSink(AudioTrackSinkInterface* sink) override {}
hbos9e302742017-01-20 10:47:10270 bool GetSignalLevel(int* level) override { return false; }
hbos09bc1282016-11-08 14:29:22271 rtc::scoped_refptr<AudioProcessorInterface> GetAudioProcessor() override {
Taylor Brandstetter64851c02021-06-24 20:32:50272 return processor_;
hbos09bc1282016-11-08 14:29:22273 }
Taylor Brandstetter64851c02021-06-24 20:32:50274
275 private:
276 rtc::scoped_refptr<FakeAudioProcessor> processor_;
hbos09bc1282016-11-08 14:29:22277};
278
Henrik Boström646fda02019-05-22 13:49:42279class FakeVideoTrackSourceForStats : public VideoTrackSourceInterface {
280 public:
281 static rtc::scoped_refptr<FakeVideoTrackSourceForStats> Create(
282 int input_width,
283 int input_height) {
Niels Möller027c7932022-01-25 12:56:07284 return rtc::make_ref_counted<FakeVideoTrackSourceForStats>(input_width,
285 input_height);
Henrik Boström646fda02019-05-22 13:49:42286 }
287
288 FakeVideoTrackSourceForStats(int input_width, int input_height)
289 : input_width_(input_width), input_height_(input_height) {}
290 ~FakeVideoTrackSourceForStats() override {}
291
292 // VideoTrackSourceInterface
293 bool is_screencast() const override { return false; }
294 absl::optional<bool> needs_denoising() const override { return false; }
295 bool GetStats(VideoTrackSourceInterface::Stats* stats) override {
296 stats->input_width = input_width_;
297 stats->input_height = input_height_;
298 return true;
299 }
300 // MediaSourceInterface (part of VideoTrackSourceInterface)
301 MediaSourceInterface::SourceState state() const override {
302 return MediaSourceInterface::SourceState::kLive;
303 }
304 bool remote() const override { return false; }
305 // NotifierInterface (part of MediaSourceInterface)
306 void RegisterObserver(ObserverInterface* observer) override {}
307 void UnregisterObserver(ObserverInterface* observer) override {}
308 // rtc::VideoSourceInterface<VideoFrame> (part of VideoTrackSourceInterface)
309 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
310 const rtc::VideoSinkWants& wants) override {}
311 void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override {}
Markus Handell6efc14b2020-05-05 18:11:13312 bool SupportsEncodedOutput() const override { return false; }
313 void GenerateKeyFrame() override {}
314 void AddEncodedSink(
315 rtc::VideoSinkInterface<RecordableEncodedFrame>* sink) override {}
316 void RemoveEncodedSink(
317 rtc::VideoSinkInterface<RecordableEncodedFrame>* sink) override {}
Henrik Boström646fda02019-05-22 13:49:42318
319 private:
320 int input_width_;
321 int input_height_;
322};
323
Yves Gerey665174f2018-06-19 13:03:05324class FakeVideoTrackForStats : public MediaStreamTrack<VideoTrackInterface> {
hbos09bc1282016-11-08 14:29:22325 public:
326 static rtc::scoped_refptr<FakeVideoTrackForStats> Create(
327 const std::string& id,
Henrik Boström646fda02019-05-22 13:49:42328 MediaStreamTrackInterface::TrackState state,
329 rtc::scoped_refptr<VideoTrackSourceInterface> source) {
Niels Möller027c7932022-01-25 12:56:07330 auto video_track =
331 rtc::make_ref_counted<FakeVideoTrackForStats>(id, std::move(source));
hbos09bc1282016-11-08 14:29:22332 video_track->set_state(state);
333 return video_track;
334 }
335
Henrik Boström646fda02019-05-22 13:49:42336 FakeVideoTrackForStats(const std::string& id,
337 rtc::scoped_refptr<VideoTrackSourceInterface> source)
338 : MediaStreamTrack<VideoTrackInterface>(id), source_(source) {}
hbos09bc1282016-11-08 14:29:22339
340 std::string kind() const override {
341 return MediaStreamTrackInterface::kVideoKind;
342 }
perkj773be362017-08-01 06:22:01343
344 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
Mirko Bonadeic4dd7302019-02-25 08:12:02345 const rtc::VideoSinkWants& wants) override {}
346 void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override {}
perkj773be362017-08-01 06:22:01347
Henrik Boström646fda02019-05-22 13:49:42348 VideoTrackSourceInterface* GetSource() const override {
349 return source_.get();
350 }
351
352 private:
353 rtc::scoped_refptr<VideoTrackSourceInterface> source_;
hbos09bc1282016-11-08 14:29:22354};
355
hbos84abeb12017-01-16 14:16:44356rtc::scoped_refptr<MediaStreamTrackInterface> CreateFakeTrack(
357 cricket::MediaType media_type,
hbos9e302742017-01-20 10:47:10358 const std::string& track_id,
Taylor Brandstetter64851c02021-06-24 20:32:50359 MediaStreamTrackInterface::TrackState track_state,
360 bool create_fake_audio_processor = false) {
hbos84abeb12017-01-16 14:16:44361 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
Taylor Brandstetter64851c02021-06-24 20:32:50362 return FakeAudioTrackForStats::Create(track_id, track_state,
363 create_fake_audio_processor);
hbos84abeb12017-01-16 14:16:44364 } else {
365 RTC_DCHECK_EQ(media_type, cricket::MEDIA_TYPE_VIDEO);
Henrik Boström646fda02019-05-22 13:49:42366 return FakeVideoTrackForStats::Create(track_id, track_state, nullptr);
hbos84abeb12017-01-16 14:16:44367 }
368}
369
Steve Anton57858b32018-02-15 23:19:50370rtc::scoped_refptr<MockRtpSenderInternal> CreateMockSender(
Henrik Boström646fda02019-05-22 13:49:42371 cricket::MediaType media_type,
372 rtc::scoped_refptr<MediaStreamTrackInterface> track,
Harald Alvestrandc72af932018-01-11 16:18:19373 uint32_t ssrc,
Harald Alvestranda3dab842018-01-14 08:18:58374 int attachment_id,
375 std::vector<std::string> local_stream_ids) {
Henrik Boström646fda02019-05-22 13:49:42376 RTC_DCHECK(!track ||
377 (track->kind() == MediaStreamTrackInterface::kAudioKind &&
378 media_type == cricket::MEDIA_TYPE_AUDIO) ||
379 (track->kind() == MediaStreamTrackInterface::kVideoKind &&
380 media_type == cricket::MEDIA_TYPE_VIDEO));
Niels Möller027c7932022-01-25 12:56:07381 auto sender = rtc::make_ref_counted<MockRtpSenderInternal>();
hbos9e302742017-01-20 10:47:10382 EXPECT_CALL(*sender, track()).WillRepeatedly(Return(track));
383 EXPECT_CALL(*sender, ssrc()).WillRepeatedly(Return(ssrc));
Henrik Boström646fda02019-05-22 13:49:42384 EXPECT_CALL(*sender, media_type()).WillRepeatedly(Return(media_type));
Henrik Boström175f06f2023-01-05 07:53:16385 EXPECT_CALL(*sender, GetParameters())
386 .WillRepeatedly(
387 Invoke([s = sender.get()]() { return s->GetParametersInternal(); }));
388 EXPECT_CALL(*sender, GetParametersInternal()).WillRepeatedly(Invoke([ssrc]() {
Yves Gerey665174f2018-06-19 13:03:05389 RtpParameters params;
390 params.encodings.push_back(RtpEncodingParameters());
391 params.encodings[0].ssrc = ssrc;
392 return params;
393 }));
Harald Alvestrandc72af932018-01-11 16:18:19394 EXPECT_CALL(*sender, AttachmentId()).WillRepeatedly(Return(attachment_id));
Harald Alvestranda3dab842018-01-14 08:18:58395 EXPECT_CALL(*sender, stream_ids()).WillRepeatedly(Return(local_stream_ids));
Alessio Bazzica049e6112021-03-18 11:55:11396 EXPECT_CALL(*sender, SetTransceiverAsStopped());
hbos9e302742017-01-20 10:47:10397 return sender;
398}
399
Steve Anton57858b32018-02-15 23:19:50400rtc::scoped_refptr<MockRtpReceiverInternal> CreateMockReceiver(
Mirko Bonadeic61ce0d2017-11-21 16:04:20401 const rtc::scoped_refptr<MediaStreamTrackInterface>& track,
Harald Alvestrandc72af932018-01-11 16:18:19402 uint32_t ssrc,
403 int attachment_id) {
Niels Möller027c7932022-01-25 12:56:07404 auto receiver = rtc::make_ref_counted<MockRtpReceiverInternal>();
hbos9e302742017-01-20 10:47:10405 EXPECT_CALL(*receiver, track()).WillRepeatedly(Return(track));
Henrik Boström175f06f2023-01-05 07:53:16406 EXPECT_CALL(*receiver, ssrc()).WillRepeatedly(Invoke([ssrc]() {
407 return ssrc;
408 }));
Harald Alvestranda3dab842018-01-14 08:18:58409 EXPECT_CALL(*receiver, streams())
410 .WillRepeatedly(
411 Return(std::vector<rtc::scoped_refptr<MediaStreamInterface>>({})));
412
Yves Gerey665174f2018-06-19 13:03:05413 EXPECT_CALL(*receiver, media_type())
414 .WillRepeatedly(
415 Return(track->kind() == MediaStreamTrackInterface::kAudioKind
416 ? cricket::MEDIA_TYPE_AUDIO
417 : cricket::MEDIA_TYPE_VIDEO));
418 EXPECT_CALL(*receiver, GetParameters()).WillRepeatedly(Invoke([ssrc]() {
419 RtpParameters params;
420 params.encodings.push_back(RtpEncodingParameters());
421 params.encodings[0].ssrc = ssrc;
422 return params;
423 }));
Harald Alvestrandc72af932018-01-11 16:18:19424 EXPECT_CALL(*receiver, AttachmentId()).WillRepeatedly(Return(attachment_id));
Tommi6589def2022-02-17 22:36:47425 EXPECT_CALL(*receiver, Stop()).WillRepeatedly(Return());
hbos9e302742017-01-20 10:47:10426 return receiver;
427}
428
Steve Anton5b387312018-02-03 00:00:20429class RTCStatsCollectorWrapper {
hbosd565b732016-08-30 21:04:35430 public:
Steve Anton5b387312018-02-03 00:00:20431 explicit RTCStatsCollectorWrapper(
432 rtc::scoped_refptr<FakePeerConnectionForStats> pc)
433 : pc_(pc),
434 stats_collector_(
Niels Möllerafb246b2022-04-20 12:26:50435 RTCStatsCollector::Create(pc.get(),
436 50 * rtc::kNumMicrosecsPerMillisec)) {}
hbosd565b732016-08-30 21:04:35437
Steve Anton5b387312018-02-03 00:00:20438 rtc::scoped_refptr<RTCStatsCollector> stats_collector() {
439 return stats_collector_;
hbosd565b732016-08-30 21:04:35440 }
441
Henrik Boström5b3541f2018-03-19 12:52:56442 rtc::scoped_refptr<const RTCStatsReport> GetStatsReport() {
443 rtc::scoped_refptr<RTCStatsObtainer> callback = RTCStatsObtainer::Create();
444 stats_collector_->GetStatsReport(callback);
445 return WaitForReport(callback);
446 }
447
448 rtc::scoped_refptr<const RTCStatsReport> GetStatsReportWithSenderSelector(
449 rtc::scoped_refptr<RtpSenderInternal> selector) {
450 rtc::scoped_refptr<RTCStatsObtainer> callback = RTCStatsObtainer::Create();
451 stats_collector_->GetStatsReport(selector, callback);
452 return WaitForReport(callback);
453 }
454
455 rtc::scoped_refptr<const RTCStatsReport> GetStatsReportWithReceiverSelector(
456 rtc::scoped_refptr<RtpReceiverInternal> selector) {
457 rtc::scoped_refptr<RTCStatsObtainer> callback = RTCStatsObtainer::Create();
458 stats_collector_->GetStatsReport(selector, callback);
459 return WaitForReport(callback);
460 }
461
Steve Anton5b387312018-02-03 00:00:20462 rtc::scoped_refptr<const RTCStatsReport> GetFreshStatsReport() {
463 stats_collector_->ClearCachedStatsReport();
464 return GetStatsReport();
465 }
466
Henrik Boström5b3541f2018-03-19 12:52:56467 rtc::scoped_refptr<MockRtpSenderInternal> SetupLocalTrackAndSender(
468 cricket::MediaType media_type,
469 const std::string& track_id,
470 uint32_t ssrc,
Henrik Boström646fda02019-05-22 13:49:42471 bool add_stream,
472 int attachment_id) {
Harald Alvestrand89061872018-01-02 13:08:34473 rtc::scoped_refptr<MediaStream> local_stream;
474 if (add_stream) {
Seth Hampson845e8782018-03-02 19:34:10475 local_stream = MediaStream::Create("LocalStreamId");
Steve Anton5b387312018-02-03 00:00:20476 pc_->mutable_local_streams()->AddStream(local_stream);
Harald Alvestrand89061872018-01-02 13:08:34477 }
hbos84abeb12017-01-16 14:16:44478
479 rtc::scoped_refptr<MediaStreamTrackInterface> track;
480 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
hbos9e302742017-01-20 10:47:10481 track = CreateFakeTrack(media_type, track_id,
482 MediaStreamTrackInterface::kLive);
Harald Alvestrand89061872018-01-02 13:08:34483 if (add_stream) {
Harald Alvestrand2f7ad282022-04-21 11:35:43484 local_stream->AddTrack(rtc::scoped_refptr<AudioTrackInterface>(
485 static_cast<AudioTrackInterface*>(track.get())));
Harald Alvestrand89061872018-01-02 13:08:34486 }
hbos84abeb12017-01-16 14:16:44487 } else {
hbos9e302742017-01-20 10:47:10488 track = CreateFakeTrack(media_type, track_id,
489 MediaStreamTrackInterface::kLive);
Harald Alvestrand89061872018-01-02 13:08:34490 if (add_stream) {
Harald Alvestrand2f7ad282022-04-21 11:35:43491 local_stream->AddTrack(rtc::scoped_refptr<VideoTrackInterface>(
492 static_cast<VideoTrackInterface*>(track.get())));
Harald Alvestrand89061872018-01-02 13:08:34493 }
hbos84abeb12017-01-16 14:16:44494 }
495
Steve Anton57858b32018-02-15 23:19:50496 rtc::scoped_refptr<MockRtpSenderInternal> sender =
Henrik Boström646fda02019-05-22 13:49:42497 CreateMockSender(media_type, track, ssrc, attachment_id, {});
Tommi6589def2022-02-17 22:36:47498 EXPECT_CALL(*sender, Stop());
499 EXPECT_CALL(*sender, SetMediaChannel(_));
Steve Anton5b387312018-02-03 00:00:20500 pc_->AddSender(sender);
Henrik Boström5b3541f2018-03-19 12:52:56501 return sender;
hbos84abeb12017-01-16 14:16:44502 }
503
Henrik Boström5b3541f2018-03-19 12:52:56504 rtc::scoped_refptr<MockRtpReceiverInternal> SetupRemoteTrackAndReceiver(
505 cricket::MediaType media_type,
506 const std::string& track_id,
507 const std::string& stream_id,
508 uint32_t ssrc) {
hbos84abeb12017-01-16 14:16:44509 rtc::scoped_refptr<MediaStream> remote_stream =
Henrik Boström5b3541f2018-03-19 12:52:56510 MediaStream::Create(stream_id);
Steve Anton5b387312018-02-03 00:00:20511 pc_->mutable_remote_streams()->AddStream(remote_stream);
hbos84abeb12017-01-16 14:16:44512
513 rtc::scoped_refptr<MediaStreamTrackInterface> track;
514 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
hbos9e302742017-01-20 10:47:10515 track = CreateFakeTrack(media_type, track_id,
516 MediaStreamTrackInterface::kLive);
Harald Alvestrand2f7ad282022-04-21 11:35:43517 remote_stream->AddTrack(rtc::scoped_refptr<AudioTrackInterface>(
518 static_cast<AudioTrackInterface*>(track.get())));
hbos84abeb12017-01-16 14:16:44519 } else {
hbos9e302742017-01-20 10:47:10520 track = CreateFakeTrack(media_type, track_id,
521 MediaStreamTrackInterface::kLive);
Harald Alvestrand2f7ad282022-04-21 11:35:43522 remote_stream->AddTrack(rtc::scoped_refptr<VideoTrackInterface>(
523 static_cast<VideoTrackInterface*>(track.get())));
hbos84abeb12017-01-16 14:16:44524 }
525
Steve Anton57858b32018-02-15 23:19:50526 rtc::scoped_refptr<MockRtpReceiverInternal> receiver =
Harald Alvestrandc72af932018-01-11 16:18:19527 CreateMockReceiver(track, ssrc, 62);
Harald Alvestranda3dab842018-01-14 08:18:58528 EXPECT_CALL(*receiver, streams())
529 .WillRepeatedly(
530 Return(std::vector<rtc::scoped_refptr<MediaStreamInterface>>(
531 {remote_stream})));
Tommi6589def2022-02-17 22:36:47532 EXPECT_CALL(*receiver, SetMediaChannel(_)).WillRepeatedly(Return());
Steve Anton5b387312018-02-03 00:00:20533 pc_->AddReceiver(receiver);
Henrik Boström5b3541f2018-03-19 12:52:56534 return receiver;
hbos84abeb12017-01-16 14:16:44535 }
536
hbos9e302742017-01-20 10:47:10537 // Attaches tracks to peer connections by configuring RTP senders and RTP
538 // receivers according to the tracks' pairings with
539 // |[Voice/Video][Sender/Receiver]Info| and their SSRCs. Local tracks can be
540 // associated with multiple |[Voice/Video]SenderInfo|s, remote tracks can only
541 // be associated with one |[Voice/Video]ReceiverInfo|.
Henrik Boström646fda02019-05-22 13:49:42542 // Senders get assigned attachment ID "ssrc + 10".
hbos9e302742017-01-20 10:47:10543 void CreateMockRtpSendersReceiversAndChannels(
Harald Alvestranda3dab842018-01-14 08:18:58544 std::initializer_list<
545 std::pair<MediaStreamTrackInterface*, cricket::VoiceSenderInfo>>
546 local_audio_track_info_pairs,
547 std::initializer_list<
548 std::pair<MediaStreamTrackInterface*, cricket::VoiceReceiverInfo>>
549 remote_audio_track_info_pairs,
550 std::initializer_list<
551 std::pair<MediaStreamTrackInterface*, cricket::VideoSenderInfo>>
552 local_video_track_info_pairs,
553 std::initializer_list<
554 std::pair<MediaStreamTrackInterface*, cricket::VideoReceiverInfo>>
555 remote_video_track_info_pairs,
556 std::vector<std::string> local_stream_ids,
557 std::vector<rtc::scoped_refptr<MediaStreamInterface>> remote_streams) {
Steve Anton5b387312018-02-03 00:00:20558 cricket::VoiceMediaInfo voice_media_info;
559 cricket::VideoMediaInfo video_media_info;
560
hbos9e302742017-01-20 10:47:10561 // Local audio tracks and voice sender infos
562 for (auto& pair : local_audio_track_info_pairs) {
563 MediaStreamTrackInterface* local_audio_track = pair.first;
564 const cricket::VoiceSenderInfo& voice_sender_info = pair.second;
565 RTC_DCHECK_EQ(local_audio_track->kind(),
566 MediaStreamTrackInterface::kAudioKind);
567
Steve Anton5b387312018-02-03 00:00:20568 voice_media_info.senders.push_back(voice_sender_info);
Steve Anton57858b32018-02-15 23:19:50569 rtc::scoped_refptr<MockRtpSenderInternal> rtp_sender = CreateMockSender(
Henrik Boström646fda02019-05-22 13:49:42570 cricket::MEDIA_TYPE_AUDIO,
Harald Alvestrandc72af932018-01-11 16:18:19571 rtc::scoped_refptr<MediaStreamTrackInterface>(local_audio_track),
Henrik Boström646fda02019-05-22 13:49:42572 voice_sender_info.local_stats[0].ssrc,
573 voice_sender_info.local_stats[0].ssrc + 10, local_stream_ids);
Tomas Gunnarsson16de2162022-01-26 09:21:57574 EXPECT_CALL(*rtp_sender, SetMediaChannel(_)).WillRepeatedly(Return());
Tommi6589def2022-02-17 22:36:47575 EXPECT_CALL(*rtp_sender, Stop());
Steve Anton5b387312018-02-03 00:00:20576 pc_->AddSender(rtp_sender);
hbos9e302742017-01-20 10:47:10577 }
Steve Anton5b387312018-02-03 00:00:20578
hbos9e302742017-01-20 10:47:10579 // Remote audio tracks and voice receiver infos
580 for (auto& pair : remote_audio_track_info_pairs) {
581 MediaStreamTrackInterface* remote_audio_track = pair.first;
582 const cricket::VoiceReceiverInfo& voice_receiver_info = pair.second;
583 RTC_DCHECK_EQ(remote_audio_track->kind(),
584 MediaStreamTrackInterface::kAudioKind);
585
Steve Anton5b387312018-02-03 00:00:20586 voice_media_info.receivers.push_back(voice_receiver_info);
Steve Anton57858b32018-02-15 23:19:50587 rtc::scoped_refptr<MockRtpReceiverInternal> rtp_receiver =
588 CreateMockReceiver(
589 rtc::scoped_refptr<MediaStreamTrackInterface>(remote_audio_track),
Henrik Boström646fda02019-05-22 13:49:42590 voice_receiver_info.local_stats[0].ssrc,
591 voice_receiver_info.local_stats[0].ssrc + 10);
Harald Alvestranda3dab842018-01-14 08:18:58592 EXPECT_CALL(*rtp_receiver, streams())
593 .WillRepeatedly(Return(remote_streams));
Tommi6589def2022-02-17 22:36:47594 EXPECT_CALL(*rtp_receiver, SetMediaChannel(_)).WillRepeatedly(Return());
Steve Anton5b387312018-02-03 00:00:20595 pc_->AddReceiver(rtp_receiver);
hbos9e302742017-01-20 10:47:10596 }
Steve Anton5b387312018-02-03 00:00:20597
hbos9e302742017-01-20 10:47:10598 // Local video tracks and video sender infos
599 for (auto& pair : local_video_track_info_pairs) {
600 MediaStreamTrackInterface* local_video_track = pair.first;
601 const cricket::VideoSenderInfo& video_sender_info = pair.second;
602 RTC_DCHECK_EQ(local_video_track->kind(),
603 MediaStreamTrackInterface::kVideoKind);
604
Steve Anton5b387312018-02-03 00:00:20605 video_media_info.senders.push_back(video_sender_info);
Henrik Boströma0ff50c2020-05-05 13:54:46606 video_media_info.aggregated_senders.push_back(video_sender_info);
Steve Anton57858b32018-02-15 23:19:50607 rtc::scoped_refptr<MockRtpSenderInternal> rtp_sender = CreateMockSender(
Henrik Boström646fda02019-05-22 13:49:42608 cricket::MEDIA_TYPE_VIDEO,
Harald Alvestrandc72af932018-01-11 16:18:19609 rtc::scoped_refptr<MediaStreamTrackInterface>(local_video_track),
Henrik Boström646fda02019-05-22 13:49:42610 video_sender_info.local_stats[0].ssrc,
611 video_sender_info.local_stats[0].ssrc + 10, local_stream_ids);
Tomas Gunnarsson16de2162022-01-26 09:21:57612 EXPECT_CALL(*rtp_sender, SetMediaChannel(_)).WillRepeatedly(Return());
Tommi6589def2022-02-17 22:36:47613 EXPECT_CALL(*rtp_sender, Stop());
Steve Anton5b387312018-02-03 00:00:20614 pc_->AddSender(rtp_sender);
hbos9e302742017-01-20 10:47:10615 }
Steve Anton5b387312018-02-03 00:00:20616
hbos9e302742017-01-20 10:47:10617 // Remote video tracks and video receiver infos
618 for (auto& pair : remote_video_track_info_pairs) {
619 MediaStreamTrackInterface* remote_video_track = pair.first;
620 const cricket::VideoReceiverInfo& video_receiver_info = pair.second;
621 RTC_DCHECK_EQ(remote_video_track->kind(),
622 MediaStreamTrackInterface::kVideoKind);
623
Steve Anton5b387312018-02-03 00:00:20624 video_media_info.receivers.push_back(video_receiver_info);
Steve Anton57858b32018-02-15 23:19:50625 rtc::scoped_refptr<MockRtpReceiverInternal> rtp_receiver =
626 CreateMockReceiver(
627 rtc::scoped_refptr<MediaStreamTrackInterface>(remote_video_track),
Henrik Boström646fda02019-05-22 13:49:42628 video_receiver_info.local_stats[0].ssrc,
629 video_receiver_info.local_stats[0].ssrc + 10);
Harald Alvestranda3dab842018-01-14 08:18:58630 EXPECT_CALL(*rtp_receiver, streams())
631 .WillRepeatedly(Return(remote_streams));
Tommi6589def2022-02-17 22:36:47632 EXPECT_CALL(*rtp_receiver, SetMediaChannel(_)).WillRepeatedly(Return());
Steve Anton5b387312018-02-03 00:00:20633 pc_->AddReceiver(rtp_receiver);
hbos9e302742017-01-20 10:47:10634 }
hbos9e302742017-01-20 10:47:10635
Tommi19015512022-02-02 10:49:35636 pc_->AddVoiceChannel("audio", "transport", voice_media_info);
637 pc_->AddVideoChannel("video", "transport", video_media_info);
hbos9e302742017-01-20 10:47:10638 }
639
hbosd565b732016-08-30 21:04:35640 private:
Henrik Boström5b3541f2018-03-19 12:52:56641 rtc::scoped_refptr<const RTCStatsReport> WaitForReport(
642 rtc::scoped_refptr<RTCStatsObtainer> callback) {
Niels Möllerafb246b2022-04-20 12:26:50643 EXPECT_TRUE_WAIT(callback->report() != nullptr, kGetStatsReportTimeoutMs);
Henrik Boström5b3541f2018-03-19 12:52:56644 int64_t after = rtc::TimeUTCMicros();
645 for (const RTCStats& stats : *callback->report()) {
Alessio Bazzicaf7b1b952021-03-23 16:23:04646 if (stats.type() == RTCRemoteInboundRtpStreamStats::kType ||
647 stats.type() == RTCRemoteOutboundRtpStreamStats::kType) {
648 // Ignore remote timestamps.
649 continue;
650 }
Philipp Hanckeb81823a2023-01-04 14:17:42651 EXPECT_LE(stats.timestamp().us(), after);
Henrik Boström5b3541f2018-03-19 12:52:56652 }
653 return callback->report();
654 }
655
Steve Anton5b387312018-02-03 00:00:20656 rtc::scoped_refptr<FakePeerConnectionForStats> pc_;
657 rtc::scoped_refptr<RTCStatsCollector> stats_collector_;
hbosd565b732016-08-30 21:04:35658};
659
Mirko Bonadei6a489f22019-04-09 13:11:12660class RTCStatsCollectorTest : public ::testing::Test {
hbosc82f2e12016-09-05 08:36:50661 public:
662 RTCStatsCollectorTest()
Niels Möller027c7932022-01-25 12:56:07663 : pc_(rtc::make_ref_counted<FakePeerConnectionForStats>()),
Tommifaf33872023-03-16 08:25:29664 stats_(new RTCStatsCollectorWrapper(pc_)),
Tommi55f72802023-03-27 10:39:33665 data_channel_controller_(
666 new FakeDataChannelController(pc_->network_thread())) {}
hbosc82f2e12016-09-05 08:36:50667
hbos6ab97ce02016-10-03 21:16:56668 void ExpectReportContainsCertificateInfo(
669 const rtc::scoped_refptr<const RTCStatsReport>& report,
hbos23368e12016-12-21 12:29:17670 const CertificateInfo& certinfo) {
671 for (size_t i = 0; i < certinfo.fingerprints.size(); ++i) {
672 RTCCertificateStats expected_certificate_stats(
Philipp Hanckeb81823a2023-01-04 14:17:42673 "CF" + certinfo.fingerprints[i], report->timestamp());
hbos23368e12016-12-21 12:29:17674 expected_certificate_stats.fingerprint = certinfo.fingerprints[i];
675 expected_certificate_stats.fingerprint_algorithm = "sha-1";
676 expected_certificate_stats.base64_certificate = certinfo.pems[i];
677 if (i + 1 < certinfo.fingerprints.size()) {
678 expected_certificate_stats.issuer_certificate_id =
Henrik Boström8dfc90f2022-09-02 07:39:29679 "CF" + certinfo.fingerprints[i + 1];
hbos6ab97ce02016-10-03 21:16:56680 }
hbos23368e12016-12-21 12:29:17681 ASSERT_TRUE(report->Get(expected_certificate_stats.id()));
682 EXPECT_EQ(expected_certificate_stats,
Yves Gerey665174f2018-06-19 13:03:05683 report->Get(expected_certificate_stats.id())
684 ->cast_to<RTCCertificateStats>());
hbos6ab97ce02016-10-03 21:16:56685 }
686 }
687
Henrik Boström69d23c92022-09-26 12:13:17688 const RTCCertificateStats* GetCertificateStatsFromFingerprint(
689 const rtc::scoped_refptr<const RTCStatsReport>& report,
690 const std::string& fingerprint) {
691 auto certificates = report->GetStatsOfType<RTCCertificateStats>();
692 for (const auto* certificate : certificates) {
693 if (*certificate->fingerprint == fingerprint) {
694 return certificate;
695 }
696 }
697 return nullptr;
698 }
699
Henrik Boström5b3541f2018-03-19 12:52:56700 struct ExampleStatsGraph {
701 rtc::scoped_refptr<RtpSenderInternal> sender;
702 rtc::scoped_refptr<RtpReceiverInternal> receiver;
703
704 rtc::scoped_refptr<const RTCStatsReport> full_report;
705 std::string send_codec_id;
706 std::string recv_codec_id;
707 std::string outbound_rtp_id;
708 std::string inbound_rtp_id;
Alessio Bazzicaf7b1b952021-03-23 16:23:04709 std::string remote_outbound_rtp_id;
Henrik Boström5b3541f2018-03-19 12:52:56710 std::string transport_id;
Henrik Boström5b3541f2018-03-19 12:52:56711 std::string peer_connection_id;
Henrik Boström646fda02019-05-22 13:49:42712 std::string media_source_id;
Henrik Boström5b3541f2018-03-19 12:52:56713 };
714
Alessio Bazzicaf7b1b952021-03-23 16:23:04715 // Sets up the example stats graph (see ASCII art below) for a video only
716 // call. The graph is used for testing the stats selection algorithm (see
717 // https://w3c.github.io/webrtc-pc/#dfn-stats-selection-algorithm).
Henrik Boström5b3541f2018-03-19 12:52:56718 // These tests test the integration of the stats traversal algorithm inside of
719 // RTCStatsCollector. See rtcstatstraveral_unittest.cc for more stats
720 // traversal tests.
721 ExampleStatsGraph SetupExampleStatsGraphForSelectorTests() {
722 ExampleStatsGraph graph;
723
724 // codec (send)
Henrik Boström8dfc90f2022-09-02 07:39:29725 graph.send_codec_id = "COTTransportName1_1";
Henrik Boström5b3541f2018-03-19 12:52:56726 cricket::VideoMediaInfo video_media_info;
727 RtpCodecParameters send_codec;
728 send_codec.payload_type = 1;
729 send_codec.clock_rate = 0;
730 video_media_info.send_codecs.insert(
731 std::make_pair(send_codec.payload_type, send_codec));
732 // codec (recv)
Henrik Boström8dfc90f2022-09-02 07:39:29733 graph.recv_codec_id = "CITTransportName1_2";
Henrik Boström5b3541f2018-03-19 12:52:56734 RtpCodecParameters recv_codec;
735 recv_codec.payload_type = 2;
736 recv_codec.clock_rate = 0;
737 video_media_info.receive_codecs.insert(
738 std::make_pair(recv_codec.payload_type, recv_codec));
739 // outbound-rtp
Henrik Boströmb43e3bb2022-09-26 10:36:44740 graph.outbound_rtp_id = "OTTransportName1V3";
Henrik Boström5b3541f2018-03-19 12:52:56741 video_media_info.senders.push_back(cricket::VideoSenderInfo());
742 video_media_info.senders[0].local_stats.push_back(
743 cricket::SsrcSenderInfo());
744 video_media_info.senders[0].local_stats[0].ssrc = 3;
745 video_media_info.senders[0].codec_payload_type = send_codec.payload_type;
Henrik Boströma0ff50c2020-05-05 13:54:46746 video_media_info.aggregated_senders.push_back(video_media_info.senders[0]);
Henrik Boström5b3541f2018-03-19 12:52:56747 // inbound-rtp
Henrik Boströmb43e3bb2022-09-26 10:36:44748 graph.inbound_rtp_id = "ITTransportName1V4";
Henrik Boström5b3541f2018-03-19 12:52:56749 video_media_info.receivers.push_back(cricket::VideoReceiverInfo());
750 video_media_info.receivers[0].local_stats.push_back(
751 cricket::SsrcReceiverInfo());
752 video_media_info.receivers[0].local_stats[0].ssrc = 4;
753 video_media_info.receivers[0].codec_payload_type = recv_codec.payload_type;
754 // transport
Henrik Boström8dfc90f2022-09-02 07:39:29755 graph.transport_id = "TTransportName1";
Tommi19015512022-02-02 10:49:35756 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström4e231ee2023-05-24 09:24:13757 // outbound-rtp's sender
Henrik Boström5b3541f2018-03-19 12:52:56758 graph.sender = stats_->SetupLocalTrackAndSender(
Henrik Boström646fda02019-05-22 13:49:42759 cricket::MEDIA_TYPE_VIDEO, "LocalVideoTrackID", 3, false, 50);
Henrik Boström4e231ee2023-05-24 09:24:13760 // inbound-rtp's receiver
Henrik Boström5b3541f2018-03-19 12:52:56761 graph.receiver = stats_->SetupRemoteTrackAndReceiver(
762 cricket::MEDIA_TYPE_VIDEO, "RemoteVideoTrackID", "RemoteStreamId", 4);
Henrik Boström5b3541f2018-03-19 12:52:56763 // peer-connection
Henrik Boström8dfc90f2022-09-02 07:39:29764 graph.peer_connection_id = "P";
Henrik Boström646fda02019-05-22 13:49:42765 // media-source (kind: video)
Henrik Boström8dfc90f2022-09-02 07:39:29766 graph.media_source_id = "SV" + rtc::ToString(graph.sender->AttachmentId());
Henrik Boström5b3541f2018-03-19 12:52:56767
768 // Expected stats graph:
769 //
Henrik Boström4e231ee2023-05-24 09:24:13770 // media-source peer-connection
771 // ^
772 // |
773 // +--------- outbound-rtp inbound-rtp
774 // | | | |
775 // v v v v
776 // codec (send) transport codec (recv)
Henrik Boström5b3541f2018-03-19 12:52:56777
778 // Verify the stats graph is set up correctly.
779 graph.full_report = stats_->GetStatsReport();
Henrik Boström4e231ee2023-05-24 09:24:13780 EXPECT_EQ(graph.full_report->size(), 7u);
Henrik Boström5b3541f2018-03-19 12:52:56781 EXPECT_TRUE(graph.full_report->Get(graph.send_codec_id));
782 EXPECT_TRUE(graph.full_report->Get(graph.recv_codec_id));
783 EXPECT_TRUE(graph.full_report->Get(graph.outbound_rtp_id));
784 EXPECT_TRUE(graph.full_report->Get(graph.inbound_rtp_id));
785 EXPECT_TRUE(graph.full_report->Get(graph.transport_id));
Henrik Boström5b3541f2018-03-19 12:52:56786 EXPECT_TRUE(graph.full_report->Get(graph.peer_connection_id));
Henrik Boström646fda02019-05-22 13:49:42787 EXPECT_TRUE(graph.full_report->Get(graph.media_source_id));
Henrik Boström5b3541f2018-03-19 12:52:56788 const auto& outbound_rtp = graph.full_report->Get(graph.outbound_rtp_id)
Philipp Hancke1f98b462023-03-07 08:53:59789 ->cast_to<RTCOutboundRtpStreamStats>();
Henrik Boström646fda02019-05-22 13:49:42790 EXPECT_EQ(*outbound_rtp.media_source_id, graph.media_source_id);
Henrik Boström5b3541f2018-03-19 12:52:56791 EXPECT_EQ(*outbound_rtp.codec_id, graph.send_codec_id);
Henrik Boström5b3541f2018-03-19 12:52:56792 EXPECT_EQ(*outbound_rtp.transport_id, graph.transport_id);
Harald Alvestrand2f553702023-03-07 10:10:03793 EXPECT_TRUE(graph.full_report->Get(graph.inbound_rtp_id));
794 // We can't use an ASSERT in a function returning non-void, so just return.
795 if (!graph.full_report->Get(graph.inbound_rtp_id)) {
796 return graph;
797 }
Henrik Boström5b3541f2018-03-19 12:52:56798 const auto& inbound_rtp = graph.full_report->Get(graph.inbound_rtp_id)
Philipp Hancke1f98b462023-03-07 08:53:59799 ->cast_to<RTCInboundRtpStreamStats>();
Henrik Boström5b3541f2018-03-19 12:52:56800 EXPECT_EQ(*inbound_rtp.codec_id, graph.recv_codec_id);
Henrik Boström5b3541f2018-03-19 12:52:56801 EXPECT_EQ(*inbound_rtp.transport_id, graph.transport_id);
802
803 return graph;
804 }
805
Alessio Bazzicaf7b1b952021-03-23 16:23:04806 // Sets up an example stats graph (see ASCII art below) for an audio only call
807 // and checks that the expected stats are generated.
808 ExampleStatsGraph SetupExampleStatsVoiceGraph(
809 bool add_remote_outbound_stats) {
810 constexpr uint32_t kLocalSsrc = 3;
811 constexpr uint32_t kRemoteSsrc = 4;
812 ExampleStatsGraph graph;
813
814 // codec (send)
Henrik Boström8dfc90f2022-09-02 07:39:29815 graph.send_codec_id = "COTTransportName1_1";
Alessio Bazzicaf7b1b952021-03-23 16:23:04816 cricket::VoiceMediaInfo media_info;
817 RtpCodecParameters send_codec;
818 send_codec.payload_type = 1;
819 send_codec.clock_rate = 0;
820 media_info.send_codecs.insert(
821 std::make_pair(send_codec.payload_type, send_codec));
822 // codec (recv)
Henrik Boström8dfc90f2022-09-02 07:39:29823 graph.recv_codec_id = "CITTransportName1_2";
Alessio Bazzicaf7b1b952021-03-23 16:23:04824 RtpCodecParameters recv_codec;
825 recv_codec.payload_type = 2;
826 recv_codec.clock_rate = 0;
827 media_info.receive_codecs.insert(
828 std::make_pair(recv_codec.payload_type, recv_codec));
829 // outbound-rtp
Henrik Boströmb43e3bb2022-09-26 10:36:44830 graph.outbound_rtp_id = "OTTransportName1A3";
Alessio Bazzicaf7b1b952021-03-23 16:23:04831 media_info.senders.push_back(cricket::VoiceSenderInfo());
832 media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
833 media_info.senders[0].local_stats[0].ssrc = kLocalSsrc;
834 media_info.senders[0].codec_payload_type = send_codec.payload_type;
835 // inbound-rtp
Henrik Boströmb43e3bb2022-09-26 10:36:44836 graph.inbound_rtp_id = "ITTransportName1A4";
Alessio Bazzicaf7b1b952021-03-23 16:23:04837 media_info.receivers.push_back(cricket::VoiceReceiverInfo());
838 media_info.receivers[0].local_stats.push_back(cricket::SsrcReceiverInfo());
839 media_info.receivers[0].local_stats[0].ssrc = kRemoteSsrc;
840 media_info.receivers[0].codec_payload_type = recv_codec.payload_type;
841 // remote-outbound-rtp
842 if (add_remote_outbound_stats) {
Henrik Boström8dfc90f2022-09-02 07:39:29843 graph.remote_outbound_rtp_id = "ROA4";
Alessio Bazzicaf7b1b952021-03-23 16:23:04844 media_info.receivers[0].last_sender_report_timestamp_ms =
845 kRemoteOutboundStatsTimestampMs;
846 media_info.receivers[0].last_sender_report_remote_timestamp_ms =
847 kRemoteOutboundStatsRemoteTimestampMs;
848 media_info.receivers[0].sender_reports_packets_sent =
849 kRemoteOutboundStatsPacketsSent;
850 media_info.receivers[0].sender_reports_bytes_sent =
851 kRemoteOutboundStatsBytesSent;
852 media_info.receivers[0].sender_reports_reports_count =
853 kRemoteOutboundStatsReportsCount;
854 }
Alessio Bazzicaf7b1b952021-03-23 16:23:04855 // transport
Henrik Boström8dfc90f2022-09-02 07:39:29856 graph.transport_id = "TTransportName1";
Tommi19015512022-02-02 10:49:35857 pc_->AddVoiceChannel("VoiceMid", "TransportName", media_info);
Henrik Boström4e231ee2023-05-24 09:24:13858 // outbound-rtp's sender
Alessio Bazzicaf7b1b952021-03-23 16:23:04859 graph.sender = stats_->SetupLocalTrackAndSender(
860 cricket::MEDIA_TYPE_AUDIO, "LocalAudioTrackID", kLocalSsrc, false, 50);
Henrik Boström4e231ee2023-05-24 09:24:13861 // inbound-rtp's receiver
Alessio Bazzicaf7b1b952021-03-23 16:23:04862 graph.receiver = stats_->SetupRemoteTrackAndReceiver(
863 cricket::MEDIA_TYPE_AUDIO, "RemoteAudioTrackID", "RemoteStreamId",
864 kRemoteSsrc);
Alessio Bazzicaf7b1b952021-03-23 16:23:04865 // peer-connection
Henrik Boström8dfc90f2022-09-02 07:39:29866 graph.peer_connection_id = "P";
Alessio Bazzicaf7b1b952021-03-23 16:23:04867 // media-source (kind: video)
Henrik Boström8dfc90f2022-09-02 07:39:29868 graph.media_source_id = "SA" + rtc::ToString(graph.sender->AttachmentId());
Alessio Bazzicaf7b1b952021-03-23 16:23:04869
870 // Expected stats graph:
871 //
Henrik Boström4e231ee2023-05-24 09:24:13872 // media-source peer-connection
873 // ^
874 // |
875 // +--------- outbound-rtp inbound-rtp
876 // | | | |
877 // v v v v
878 // codec (send) transport codec (recv)
Alessio Bazzicaf7b1b952021-03-23 16:23:04879
880 // Verify the stats graph is set up correctly.
881 graph.full_report = stats_->GetStatsReport();
Henrik Boström4e231ee2023-05-24 09:24:13882 EXPECT_EQ(graph.full_report->size(), add_remote_outbound_stats ? 8u : 7u);
Alessio Bazzicaf7b1b952021-03-23 16:23:04883 EXPECT_TRUE(graph.full_report->Get(graph.send_codec_id));
884 EXPECT_TRUE(graph.full_report->Get(graph.recv_codec_id));
885 EXPECT_TRUE(graph.full_report->Get(graph.outbound_rtp_id));
886 EXPECT_TRUE(graph.full_report->Get(graph.inbound_rtp_id));
887 EXPECT_TRUE(graph.full_report->Get(graph.transport_id));
Alessio Bazzicaf7b1b952021-03-23 16:23:04888 EXPECT_TRUE(graph.full_report->Get(graph.peer_connection_id));
889 EXPECT_TRUE(graph.full_report->Get(graph.media_source_id));
890 // `graph.remote_outbound_rtp_id` is omitted on purpose so that expectations
891 // can be added by the caller depending on what value it sets for the
892 // `add_remote_outbound_stats` argument.
Alessio Bazzicaf7b1b952021-03-23 16:23:04893 const auto& outbound_rtp = graph.full_report->Get(graph.outbound_rtp_id)
Philipp Hancke1f98b462023-03-07 08:53:59894 ->cast_to<RTCOutboundRtpStreamStats>();
Alessio Bazzicaf7b1b952021-03-23 16:23:04895 EXPECT_EQ(*outbound_rtp.media_source_id, graph.media_source_id);
896 EXPECT_EQ(*outbound_rtp.codec_id, graph.send_codec_id);
Alessio Bazzicaf7b1b952021-03-23 16:23:04897 EXPECT_EQ(*outbound_rtp.transport_id, graph.transport_id);
Harald Alvestrand2f553702023-03-07 10:10:03898 EXPECT_TRUE(graph.full_report->Get(graph.inbound_rtp_id));
899 // We can't use ASSERT in a function with a return value.
900 if (!graph.full_report->Get(graph.inbound_rtp_id)) {
901 return graph;
902 }
Alessio Bazzicaf7b1b952021-03-23 16:23:04903 const auto& inbound_rtp = graph.full_report->Get(graph.inbound_rtp_id)
Philipp Hancke1f98b462023-03-07 08:53:59904 ->cast_to<RTCInboundRtpStreamStats>();
Alessio Bazzicaf7b1b952021-03-23 16:23:04905 EXPECT_EQ(*inbound_rtp.codec_id, graph.recv_codec_id);
Alessio Bazzicaf7b1b952021-03-23 16:23:04906 EXPECT_EQ(*inbound_rtp.transport_id, graph.transport_id);
907
908 return graph;
909 }
910
hbosc82f2e12016-09-05 08:36:50911 protected:
Steve Anton5b387312018-02-03 00:00:20912 rtc::ScopedFakeClock fake_clock_;
Niels Möller83830f32022-05-20 07:12:57913 rtc::AutoThread main_thread_;
Steve Anton5b387312018-02-03 00:00:20914 rtc::scoped_refptr<FakePeerConnectionForStats> pc_;
915 std::unique_ptr<RTCStatsCollectorWrapper> stats_;
Tommifaf33872023-03-16 08:25:29916 std::unique_ptr<FakeDataChannelController> data_channel_controller_;
hbosc82f2e12016-09-05 08:36:50917};
918
919TEST_F(RTCStatsCollectorTest, SingleCallback) {
920 rtc::scoped_refptr<const RTCStatsReport> result;
Steve Anton5b387312018-02-03 00:00:20921 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&result));
Niels Möllerafb246b2022-04-20 12:26:50922 EXPECT_TRUE_WAIT(result != nullptr, kGetStatsReportTimeoutMs);
hbosc82f2e12016-09-05 08:36:50923}
924
925TEST_F(RTCStatsCollectorTest, MultipleCallbacks) {
Steve Anton5b387312018-02-03 00:00:20926 rtc::scoped_refptr<const RTCStatsReport> a, b, c;
927 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&a));
928 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&b));
929 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&c));
Niels Möllerafb246b2022-04-20 12:26:50930 EXPECT_TRUE_WAIT(a != nullptr, kGetStatsReportTimeoutMs);
931 EXPECT_TRUE_WAIT(b != nullptr, kGetStatsReportTimeoutMs);
932 EXPECT_TRUE_WAIT(c != nullptr, kGetStatsReportTimeoutMs);
Steve Anton5b387312018-02-03 00:00:20933
hbosc82f2e12016-09-05 08:36:50934 EXPECT_EQ(a.get(), b.get());
935 EXPECT_EQ(b.get(), c.get());
936}
937
938TEST_F(RTCStatsCollectorTest, CachedStatsReports) {
Artem Titov880fa812021-07-30 20:30:23939 // Caching should ensure `a` and `b` are the same report.
Steve Anton5b387312018-02-03 00:00:20940 rtc::scoped_refptr<const RTCStatsReport> a = stats_->GetStatsReport();
941 rtc::scoped_refptr<const RTCStatsReport> b = stats_->GetStatsReport();
hbosd565b732016-08-30 21:04:35942 EXPECT_EQ(a.get(), b.get());
943 // Invalidate cache by clearing it.
Steve Anton5b387312018-02-03 00:00:20944 stats_->stats_collector()->ClearCachedStatsReport();
945 rtc::scoped_refptr<const RTCStatsReport> c = stats_->GetStatsReport();
hbosd565b732016-08-30 21:04:35946 EXPECT_NE(b.get(), c.get());
947 // Invalidate cache by advancing time.
Danil Chapovalov0c626af2020-02-10 10:16:00948 fake_clock_.AdvanceTime(TimeDelta::Millis(51));
Steve Anton5b387312018-02-03 00:00:20949 rtc::scoped_refptr<const RTCStatsReport> d = stats_->GetStatsReport();
hbosd565b732016-08-30 21:04:35950 EXPECT_TRUE(d);
951 EXPECT_NE(c.get(), d.get());
952}
953
hbosc82f2e12016-09-05 08:36:50954TEST_F(RTCStatsCollectorTest, MultipleCallbacksWithInvalidatedCacheInBetween) {
Steve Anton5b387312018-02-03 00:00:20955 rtc::scoped_refptr<const RTCStatsReport> a, b, c;
956 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&a));
957 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&b));
hbosc82f2e12016-09-05 08:36:50958 // Cache is invalidated after 50 ms.
Danil Chapovalov0c626af2020-02-10 10:16:00959 fake_clock_.AdvanceTime(TimeDelta::Millis(51));
Steve Anton5b387312018-02-03 00:00:20960 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&c));
Niels Möllerafb246b2022-04-20 12:26:50961 EXPECT_TRUE_WAIT(a != nullptr, kGetStatsReportTimeoutMs);
962 EXPECT_TRUE_WAIT(b != nullptr, kGetStatsReportTimeoutMs);
963 EXPECT_TRUE_WAIT(c != nullptr, kGetStatsReportTimeoutMs);
hbosc82f2e12016-09-05 08:36:50964 EXPECT_EQ(a.get(), b.get());
Artem Titov880fa812021-07-30 20:30:23965 // The act of doing `AdvanceTime` processes all messages. If this was not the
966 // case we might not require `c` to be fresher than `b`.
hbosc82f2e12016-09-05 08:36:50967 EXPECT_NE(c.get(), b.get());
968}
969
Harald Alvestrand910cdc22020-01-09 11:58:23970TEST_F(RTCStatsCollectorTest, ToJsonProducesParseableJson) {
971 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
972 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
973 std::string json_format = report->ToJson();
Mirko Bonadeie99f6872021-06-24 13:24:59974
975 Json::CharReaderBuilder builder;
Harald Alvestrand910cdc22020-01-09 11:58:23976 Json::Value json_value;
Mirko Bonadeie99f6872021-06-24 13:24:59977 std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
978 ASSERT_TRUE(reader->parse(json_format.c_str(),
979 json_format.c_str() + json_format.size(),
980 &json_value, nullptr));
981
Harald Alvestrand910cdc22020-01-09 11:58:23982 // A very brief sanity check on the result.
983 EXPECT_EQ(report->size(), json_value.size());
984}
985
hbos6ab97ce02016-10-03 21:16:56986TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsSingle) {
Steve Anton5b387312018-02-03 00:00:20987 const char kTransportName[] = "transport";
988
989 pc_->AddVoiceChannel("audio", kTransportName);
990
hbos6ab97ce02016-10-03 21:16:56991 std::unique_ptr<CertificateInfo> local_certinfo =
992 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 13:03:05993 std::vector<std::string>({"(local) single certificate"}));
Steve Anton5b387312018-02-03 00:00:20994 pc_->SetLocalCertificate(kTransportName, local_certinfo->certificate);
995
hbos6ab97ce02016-10-03 21:16:56996 std::unique_ptr<CertificateInfo> remote_certinfo =
997 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 13:03:05998 std::vector<std::string>({"(remote) single certificate"}));
Taylor Brandstetterc3928662018-02-23 21:04:51999 pc_->SetRemoteCertChain(
Benjamin Wright6c6c9df2018-10-25 08:16:261000 kTransportName,
1001 remote_certinfo->certificate->GetSSLCertificateChain().Clone());
hbos6ab97ce02016-10-03 21:16:561002
Steve Anton5b387312018-02-03 00:00:201003 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos6ab97ce02016-10-03 21:16:561004
hbos23368e12016-12-21 12:29:171005 ExpectReportContainsCertificateInfo(report, *local_certinfo);
1006 ExpectReportContainsCertificateInfo(report, *remote_certinfo);
hbos6ab97ce02016-10-03 21:16:561007}
1008
Henrik Boströmda6297d2022-09-19 09:33:231009// These SSRC collisions are legal.
1010TEST_F(RTCStatsCollectorTest, ValidSsrcCollisionDoesNotCrash) {
1011 // BUNDLE audio/video inbound/outbound. Unique SSRCs needed within the BUNDLE.
1012 cricket::VoiceMediaInfo mid1_info;
1013 mid1_info.receivers.emplace_back();
1014 mid1_info.receivers[0].add_ssrc(1);
1015 mid1_info.senders.emplace_back();
1016 mid1_info.senders[0].add_ssrc(2);
1017 pc_->AddVoiceChannel("Mid1", "Transport1", mid1_info);
1018 cricket::VideoMediaInfo mid2_info;
1019 mid2_info.receivers.emplace_back();
1020 mid2_info.receivers[0].add_ssrc(3);
1021 mid2_info.senders.emplace_back();
1022 mid2_info.senders[0].add_ssrc(4);
1023 pc_->AddVideoChannel("Mid2", "Transport1", mid2_info);
1024 // Now create a second BUNDLE group with SSRCs colliding with the first group
1025 // (but again no collisions within the group).
1026 cricket::VoiceMediaInfo mid3_info;
1027 mid3_info.receivers.emplace_back();
1028 mid3_info.receivers[0].add_ssrc(1);
1029 mid3_info.senders.emplace_back();
1030 mid3_info.senders[0].add_ssrc(2);
1031 pc_->AddVoiceChannel("Mid3", "Transport2", mid3_info);
1032 cricket::VideoMediaInfo mid4_info;
1033 mid4_info.receivers.emplace_back();
1034 mid4_info.receivers[0].add_ssrc(3);
1035 mid4_info.senders.emplace_back();
1036 mid4_info.senders[0].add_ssrc(4);
1037 pc_->AddVideoChannel("Mid4", "Transport2", mid4_info);
1038
1039 // This should not crash (https://crbug.com/1361612).
1040 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Philipp Hancke1f98b462023-03-07 08:53:591041 auto inbound_rtps = report->GetStatsOfType<RTCInboundRtpStreamStats>();
1042 auto outbound_rtps = report->GetStatsOfType<RTCOutboundRtpStreamStats>();
Henrik Boströmb43e3bb2022-09-26 10:36:441043 EXPECT_EQ(inbound_rtps.size(), 4u);
1044 EXPECT_EQ(outbound_rtps.size(), 4u);
Henrik Boströmda6297d2022-09-19 09:33:231045}
1046
1047// These SSRC collisions are illegal, so it is not clear if this setup can
1048// happen even when talking to a malicious endpoint, but simulate illegal SSRC
1049// collisions just to make sure we don't crash in even the most extreme cases.
1050TEST_F(RTCStatsCollectorTest, InvalidSsrcCollisionDoesNotCrash) {
1051 // One SSRC to rule them all.
1052 cricket::VoiceMediaInfo mid1_info;
1053 mid1_info.receivers.emplace_back();
1054 mid1_info.receivers[0].add_ssrc(1);
1055 mid1_info.senders.emplace_back();
1056 mid1_info.senders[0].add_ssrc(1);
1057 pc_->AddVoiceChannel("Mid1", "BundledTransport", mid1_info);
1058 cricket::VideoMediaInfo mid2_info;
1059 mid2_info.receivers.emplace_back();
1060 mid2_info.receivers[0].add_ssrc(1);
1061 mid2_info.senders.emplace_back();
1062 mid2_info.senders[0].add_ssrc(1);
1063 pc_->AddVideoChannel("Mid2", "BundledTransport", mid2_info);
1064 cricket::VoiceMediaInfo mid3_info;
1065 mid3_info.receivers.emplace_back();
1066 mid3_info.receivers[0].add_ssrc(1);
1067 mid3_info.senders.emplace_back();
1068 mid3_info.senders[0].add_ssrc(1);
1069 pc_->AddVoiceChannel("Mid3", "BundledTransport", mid3_info);
1070 cricket::VideoMediaInfo mid4_info;
1071 mid4_info.receivers.emplace_back();
1072 mid4_info.receivers[0].add_ssrc(1);
1073 mid4_info.senders.emplace_back();
1074 mid4_info.senders[0].add_ssrc(1);
1075 pc_->AddVideoChannel("Mid4", "BundledTransport", mid4_info);
1076
1077 // This should not crash (https://crbug.com/1361612).
1078 stats_->GetStatsReport();
1079 // Because this setup is illegal, there is no "right answer" to how the report
1080 // should look. We only care about not crashing.
1081}
1082
Henrik Boström31c373b2022-09-26 12:56:211083TEST_F(RTCStatsCollectorTest, CollectRTCCodecStatsOnlyIfReferenced) {
hbos0adb8282016-11-23 10:32:061084 // Audio
1085 cricket::VoiceMediaInfo voice_media_info;
1086
1087 RtpCodecParameters inbound_audio_codec;
1088 inbound_audio_codec.payload_type = 1;
deadbeefe702b302017-02-04 20:09:011089 inbound_audio_codec.kind = cricket::MEDIA_TYPE_AUDIO;
1090 inbound_audio_codec.name = "opus";
Oskar Sundbomcbc71b22017-11-16 09:56:071091 inbound_audio_codec.clock_rate = 1337;
Johannes Kron72d69152020-02-10 13:05:551092 inbound_audio_codec.num_channels = 1;
1093 inbound_audio_codec.parameters = {{"minptime", "10"}, {"useinbandfec", "1"}};
hbos0adb8282016-11-23 10:32:061094 voice_media_info.receive_codecs.insert(
1095 std::make_pair(inbound_audio_codec.payload_type, inbound_audio_codec));
1096
1097 RtpCodecParameters outbound_audio_codec;
1098 outbound_audio_codec.payload_type = 2;
deadbeefe702b302017-02-04 20:09:011099 outbound_audio_codec.kind = cricket::MEDIA_TYPE_AUDIO;
1100 outbound_audio_codec.name = "isac";
Oskar Sundbomcbc71b22017-11-16 09:56:071101 outbound_audio_codec.clock_rate = 1338;
Johannes Kron72d69152020-02-10 13:05:551102 outbound_audio_codec.num_channels = 2;
hbos0adb8282016-11-23 10:32:061103 voice_media_info.send_codecs.insert(
1104 std::make_pair(outbound_audio_codec.payload_type, outbound_audio_codec));
1105
hbos0adb8282016-11-23 10:32:061106 // Video
1107 cricket::VideoMediaInfo video_media_info;
1108
1109 RtpCodecParameters inbound_video_codec;
1110 inbound_video_codec.payload_type = 3;
deadbeefe702b302017-02-04 20:09:011111 inbound_video_codec.kind = cricket::MEDIA_TYPE_VIDEO;
1112 inbound_video_codec.name = "H264";
Oskar Sundbomcbc71b22017-11-16 09:56:071113 inbound_video_codec.clock_rate = 1339;
Johannes Kron72d69152020-02-10 13:05:551114 inbound_video_codec.parameters = {{"level-asymmetry-allowed", "1"},
1115 {"packetization-mode", "1"},
1116 {"profile-level-id", "42001f"}};
hbos0adb8282016-11-23 10:32:061117 video_media_info.receive_codecs.insert(
1118 std::make_pair(inbound_video_codec.payload_type, inbound_video_codec));
1119
1120 RtpCodecParameters outbound_video_codec;
1121 outbound_video_codec.payload_type = 4;
deadbeefe702b302017-02-04 20:09:011122 outbound_video_codec.kind = cricket::MEDIA_TYPE_VIDEO;
1123 outbound_video_codec.name = "VP8";
Oskar Sundbomcbc71b22017-11-16 09:56:071124 outbound_video_codec.clock_rate = 1340;
hbos0adb8282016-11-23 10:32:061125 video_media_info.send_codecs.insert(
1126 std::make_pair(outbound_video_codec.payload_type, outbound_video_codec));
1127
Henrik Boström31c373b2022-09-26 12:56:211128 // Ensure the above codecs are referenced.
1129 cricket::VoiceReceiverInfo inbound_audio_info;
1130 inbound_audio_info.add_ssrc(10);
1131 inbound_audio_info.codec_payload_type = 1;
1132 voice_media_info.receivers.push_back(inbound_audio_info);
1133
1134 cricket::VoiceSenderInfo outbound_audio_info;
1135 outbound_audio_info.add_ssrc(20);
1136 outbound_audio_info.codec_payload_type = 2;
1137 voice_media_info.senders.push_back(outbound_audio_info);
1138
1139 cricket::VideoReceiverInfo inbound_video_info;
1140 inbound_video_info.add_ssrc(30);
1141 inbound_video_info.codec_payload_type = 3;
1142 video_media_info.receivers.push_back(inbound_video_info);
1143
1144 cricket::VideoSenderInfo outbound_video_info;
1145 outbound_video_info.add_ssrc(40);
1146 outbound_video_info.codec_payload_type = 4;
1147 video_media_info.senders.push_back(outbound_video_info);
1148
Harald Alvestrand2f553702023-03-07 10:10:031149 auto audio_channels =
Henrik Boström31c373b2022-09-26 12:56:211150 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Harald Alvestrand2f553702023-03-07 10:10:031151 auto video_channels =
Henrik Boström31c373b2022-09-26 12:56:211152 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
hbos0adb8282016-11-23 10:32:061153
Steve Anton5b387312018-02-03 00:00:201154 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos0adb8282016-11-23 10:32:061155
Henrik Boströmb2be3922022-09-02 07:37:081156 RTCCodecStats expected_inbound_audio_codec(
Philipp Hanckeb81823a2023-01-04 14:17:421157 "CITTransportName1_1_minptime=10;useinbandfec=1", report->timestamp());
hbos0adb8282016-11-23 10:32:061158 expected_inbound_audio_codec.payload_type = 1;
hbos13f54b22017-02-28 14:56:041159 expected_inbound_audio_codec.mime_type = "audio/opus";
hbos0adb8282016-11-23 10:32:061160 expected_inbound_audio_codec.clock_rate = 1337;
Johannes Kron72d69152020-02-10 13:05:551161 expected_inbound_audio_codec.channels = 1;
1162 expected_inbound_audio_codec.sdp_fmtp_line = "minptime=10;useinbandfec=1";
Henrik Boström8dfc90f2022-09-02 07:39:291163 expected_inbound_audio_codec.transport_id = "TTransportName1";
hbos0adb8282016-11-23 10:32:061164
Henrik Boström8dfc90f2022-09-02 07:39:291165 RTCCodecStats expected_outbound_audio_codec("COTTransportName1_2",
Philipp Hanckeb81823a2023-01-04 14:17:421166 report->timestamp());
hbos0adb8282016-11-23 10:32:061167 expected_outbound_audio_codec.payload_type = 2;
hbos13f54b22017-02-28 14:56:041168 expected_outbound_audio_codec.mime_type = "audio/isac";
hbos0adb8282016-11-23 10:32:061169 expected_outbound_audio_codec.clock_rate = 1338;
Johannes Kron72d69152020-02-10 13:05:551170 expected_outbound_audio_codec.channels = 2;
Henrik Boström8dfc90f2022-09-02 07:39:291171 expected_outbound_audio_codec.transport_id = "TTransportName1";
hbos0adb8282016-11-23 10:32:061172
Henrik Boströmb2be3922022-09-02 07:37:081173 RTCCodecStats expected_inbound_video_codec(
Henrik Boström8dfc90f2022-09-02 07:39:291174 "CITTransportName1_3_level-asymmetry-allowed=1;"
Henrik Boströmb2be3922022-09-02 07:37:081175 "packetization-mode=1;profile-level-id=42001f",
Philipp Hanckeb81823a2023-01-04 14:17:421176 report->timestamp());
hbos0adb8282016-11-23 10:32:061177 expected_inbound_video_codec.payload_type = 3;
hbos13f54b22017-02-28 14:56:041178 expected_inbound_video_codec.mime_type = "video/H264";
hbos0adb8282016-11-23 10:32:061179 expected_inbound_video_codec.clock_rate = 1339;
Johannes Kron72d69152020-02-10 13:05:551180 expected_inbound_video_codec.sdp_fmtp_line =
1181 "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f";
Henrik Boström8dfc90f2022-09-02 07:39:291182 expected_inbound_video_codec.transport_id = "TTransportName1";
hbos0adb8282016-11-23 10:32:061183
Henrik Boström8dfc90f2022-09-02 07:39:291184 RTCCodecStats expected_outbound_video_codec("COTTransportName1_4",
Philipp Hanckeb81823a2023-01-04 14:17:421185 report->timestamp());
hbos0adb8282016-11-23 10:32:061186 expected_outbound_video_codec.payload_type = 4;
hbos13f54b22017-02-28 14:56:041187 expected_outbound_video_codec.mime_type = "video/VP8";
hbos0adb8282016-11-23 10:32:061188 expected_outbound_video_codec.clock_rate = 1340;
Henrik Boström8dfc90f2022-09-02 07:39:291189 expected_outbound_video_codec.transport_id = "TTransportName1";
hbos0adb8282016-11-23 10:32:061190
nissec8ee8822017-01-18 15:20:551191 ASSERT_TRUE(report->Get(expected_inbound_audio_codec.id()));
Yves Gerey665174f2018-06-19 13:03:051192 EXPECT_EQ(
1193 expected_inbound_audio_codec,
1194 report->Get(expected_inbound_audio_codec.id())->cast_to<RTCCodecStats>());
hbos0adb8282016-11-23 10:32:061195
nissec8ee8822017-01-18 15:20:551196 ASSERT_TRUE(report->Get(expected_outbound_audio_codec.id()));
hbos0adb8282016-11-23 10:32:061197 EXPECT_EQ(expected_outbound_audio_codec,
Yves Gerey665174f2018-06-19 13:03:051198 report->Get(expected_outbound_audio_codec.id())
1199 ->cast_to<RTCCodecStats>());
hbos0adb8282016-11-23 10:32:061200
nissec8ee8822017-01-18 15:20:551201 ASSERT_TRUE(report->Get(expected_inbound_video_codec.id()));
Yves Gerey665174f2018-06-19 13:03:051202 EXPECT_EQ(
1203 expected_inbound_video_codec,
1204 report->Get(expected_inbound_video_codec.id())->cast_to<RTCCodecStats>());
hbos0adb8282016-11-23 10:32:061205
nissec8ee8822017-01-18 15:20:551206 ASSERT_TRUE(report->Get(expected_outbound_video_codec.id()));
hbos0adb8282016-11-23 10:32:061207 EXPECT_EQ(expected_outbound_video_codec,
Yves Gerey665174f2018-06-19 13:03:051208 report->Get(expected_outbound_video_codec.id())
1209 ->cast_to<RTCCodecStats>());
Henrik Boström31c373b2022-09-26 12:56:211210
1211 // Now remove all the RTP streams such that there are no live codecId
1212 // references to the codecs, this should result in none of the RTCCodecStats
1213 // being exposed, despite `send_codecs` and `receive_codecs` still being set.
1214 voice_media_info.senders.clear();
1215 voice_media_info.receivers.clear();
Harald Alvestrand2f553702023-03-07 10:10:031216 audio_channels.first->SetStats(voice_media_info);
1217 audio_channels.second->SetStats(voice_media_info);
Henrik Boström31c373b2022-09-26 12:56:211218 video_media_info.senders.clear();
1219 video_media_info.receivers.clear();
Harald Alvestrand2f553702023-03-07 10:10:031220 video_channels.first->SetStats(video_media_info);
1221 video_channels.second->SetStats(video_media_info);
Henrik Boström31c373b2022-09-26 12:56:211222 stats_->stats_collector()->ClearCachedStatsReport();
1223 report = stats_->GetStatsReport();
1224 EXPECT_FALSE(report->Get(expected_inbound_audio_codec.id()));
1225 EXPECT_FALSE(report->Get(expected_outbound_audio_codec.id()));
1226 EXPECT_FALSE(report->Get(expected_inbound_video_codec.id()));
1227 EXPECT_FALSE(report->Get(expected_outbound_video_codec.id()));
hbos0adb8282016-11-23 10:32:061228}
1229
Henrik Boströmb2be3922022-09-02 07:37:081230TEST_F(RTCStatsCollectorTest, CodecStatsAreCollectedPerTransport) {
1231 // PT=10
1232 RtpCodecParameters outbound_codec_pt10;
1233 outbound_codec_pt10.payload_type = 10;
1234 outbound_codec_pt10.kind = cricket::MEDIA_TYPE_VIDEO;
1235 outbound_codec_pt10.name = "VP8";
1236 outbound_codec_pt10.clock_rate = 9000;
1237
1238 // PT=11
1239 RtpCodecParameters outbound_codec_pt11;
1240 outbound_codec_pt11.payload_type = 11;
1241 outbound_codec_pt11.kind = cricket::MEDIA_TYPE_VIDEO;
1242 outbound_codec_pt11.name = "VP8";
1243 outbound_codec_pt11.clock_rate = 9000;
1244
Henrik Boström31c373b2022-09-26 12:56:211245 // Insert codecs into `send_codecs` and ensure the PTs are referenced by RTP
1246 // streams.
Henrik Boströmb2be3922022-09-02 07:37:081247 cricket::VideoMediaInfo info_pt10;
1248 info_pt10.send_codecs.insert(
1249 std::make_pair(outbound_codec_pt10.payload_type, outbound_codec_pt10));
Henrik Boström31c373b2022-09-26 12:56:211250 info_pt10.senders.emplace_back();
1251 info_pt10.senders[0].add_ssrc(42);
1252 info_pt10.senders[0].codec_payload_type = outbound_codec_pt10.payload_type;
1253
Henrik Boströmb2be3922022-09-02 07:37:081254 cricket::VideoMediaInfo info_pt11;
1255 info_pt11.send_codecs.insert(
1256 std::make_pair(outbound_codec_pt11.payload_type, outbound_codec_pt11));
Henrik Boström31c373b2022-09-26 12:56:211257 info_pt11.senders.emplace_back();
1258 info_pt11.senders[0].add_ssrc(43);
1259 info_pt11.senders[0].codec_payload_type = outbound_codec_pt11.payload_type;
1260
Henrik Boströmb2be3922022-09-02 07:37:081261 cricket::VideoMediaInfo info_pt10_pt11;
1262 info_pt10_pt11.send_codecs.insert(
1263 std::make_pair(outbound_codec_pt10.payload_type, outbound_codec_pt10));
1264 info_pt10_pt11.send_codecs.insert(
1265 std::make_pair(outbound_codec_pt11.payload_type, outbound_codec_pt11));
Henrik Boström31c373b2022-09-26 12:56:211266 info_pt10_pt11.senders.emplace_back();
1267 info_pt10_pt11.senders[0].add_ssrc(44);
1268 info_pt10_pt11.senders[0].codec_payload_type =
1269 outbound_codec_pt10.payload_type;
1270 info_pt10_pt11.senders.emplace_back();
1271 info_pt10_pt11.senders[1].add_ssrc(45);
1272 info_pt10_pt11.senders[1].codec_payload_type =
1273 outbound_codec_pt11.payload_type;
Henrik Boströmb2be3922022-09-02 07:37:081274
1275 // First two mids contain subsets, the third one contains all PTs.
1276 pc_->AddVideoChannel("Mid1", "FirstTransport", info_pt10);
1277 pc_->AddVideoChannel("Mid2", "FirstTransport", info_pt11);
1278 pc_->AddVideoChannel("Mid3", "FirstTransport", info_pt10_pt11);
1279
1280 // There should be no duplicate codecs because all codec references are on the
1281 // same transport.
1282 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1283 auto codec_stats = report->GetStatsOfType<RTCCodecStats>();
1284 EXPECT_EQ(codec_stats.size(), 2u);
1285
1286 // If a second transport is added with the same PT information, this does
1287 // count as different codec objects.
1288 pc_->AddVideoChannel("Mid4", "SecondTransport", info_pt10_pt11);
1289 stats_->stats_collector()->ClearCachedStatsReport();
1290 report = stats_->GetStatsReport();
1291 codec_stats = report->GetStatsOfType<RTCCodecStats>();
1292 EXPECT_EQ(codec_stats.size(), 4u);
1293}
1294
1295TEST_F(RTCStatsCollectorTest, SamePayloadTypeButDifferentFmtpLines) {
1296 // PT=111, useinbandfec=0
1297 RtpCodecParameters inbound_codec_pt111_nofec;
1298 inbound_codec_pt111_nofec.payload_type = 111;
1299 inbound_codec_pt111_nofec.kind = cricket::MEDIA_TYPE_AUDIO;
1300 inbound_codec_pt111_nofec.name = "opus";
1301 inbound_codec_pt111_nofec.clock_rate = 48000;
1302 inbound_codec_pt111_nofec.parameters.insert(
1303 std::make_pair("useinbandfec", "0"));
1304
1305 // PT=111, useinbandfec=1
1306 RtpCodecParameters inbound_codec_pt111_fec;
1307 inbound_codec_pt111_fec.payload_type = 111;
1308 inbound_codec_pt111_fec.kind = cricket::MEDIA_TYPE_AUDIO;
1309 inbound_codec_pt111_fec.name = "opus";
1310 inbound_codec_pt111_fec.clock_rate = 48000;
1311 inbound_codec_pt111_fec.parameters.insert(
1312 std::make_pair("useinbandfec", "1"));
1313
1314 cricket::VideoMediaInfo info_nofec;
Henrik Boström31c373b2022-09-26 12:56:211315 info_nofec.receive_codecs.insert(std::make_pair(
Henrik Boströmb2be3922022-09-02 07:37:081316 inbound_codec_pt111_nofec.payload_type, inbound_codec_pt111_nofec));
Henrik Boström31c373b2022-09-26 12:56:211317 info_nofec.receivers.emplace_back();
1318 info_nofec.receivers[0].add_ssrc(123);
1319 info_nofec.receivers[0].codec_payload_type =
1320 inbound_codec_pt111_nofec.payload_type;
Henrik Boströmb2be3922022-09-02 07:37:081321 cricket::VideoMediaInfo info_fec;
Henrik Boström31c373b2022-09-26 12:56:211322 info_fec.receive_codecs.insert(std::make_pair(
Henrik Boströmb2be3922022-09-02 07:37:081323 inbound_codec_pt111_fec.payload_type, inbound_codec_pt111_fec));
Henrik Boström31c373b2022-09-26 12:56:211324 info_fec.receivers.emplace_back();
1325 info_fec.receivers[0].add_ssrc(321);
1326 info_fec.receivers[0].codec_payload_type =
1327 inbound_codec_pt111_fec.payload_type;
Henrik Boströmb2be3922022-09-02 07:37:081328
1329 // First two mids contain subsets, the third one contains all PTs.
1330 pc_->AddVideoChannel("Mid1", "BundledTransport", info_nofec);
1331 pc_->AddVideoChannel("Mid2", "BundledTransport", info_fec);
1332
1333 // Despite having the same PT we should see two codec stats because their FMTP
1334 // lines are different.
1335 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1336 auto codec_stats = report->GetStatsOfType<RTCCodecStats>();
1337 EXPECT_EQ(codec_stats.size(), 2u);
1338
Henrik Boström31c373b2022-09-26 12:56:211339 // Ensure SSRC uniqueness before the next AddVideoChannel() call. SSRCs need
1340 // to be unique on different m= sections when using BUNDLE.
1341 info_nofec.receivers[0].local_stats[0].ssrc = 12;
1342 info_fec.receivers[0].local_stats[0].ssrc = 21;
Henrik Boströmb2be3922022-09-02 07:37:081343 // Adding more m= sections that does have the same FMTP lines does not result
1344 // in duplicates.
1345 pc_->AddVideoChannel("Mid3", "BundledTransport", info_nofec);
1346 pc_->AddVideoChannel("Mid4", "BundledTransport", info_fec);
1347 stats_->stats_collector()->ClearCachedStatsReport();
1348 report = stats_->GetStatsReport();
1349 codec_stats = report->GetStatsOfType<RTCCodecStats>();
1350 EXPECT_EQ(codec_stats.size(), 2u);
1351
1352 // Same FMTP line but a different PT does count as a new codec.
1353 // PT=112, useinbandfec=1
1354 RtpCodecParameters inbound_codec_pt112_fec;
1355 inbound_codec_pt112_fec.payload_type = 112;
1356 inbound_codec_pt112_fec.kind = cricket::MEDIA_TYPE_AUDIO;
1357 inbound_codec_pt112_fec.name = "opus";
1358 inbound_codec_pt112_fec.clock_rate = 48000;
1359 inbound_codec_pt112_fec.parameters.insert(
1360 std::make_pair("useinbandfec", "1"));
1361 cricket::VideoMediaInfo info_fec_pt112;
Henrik Boström31c373b2022-09-26 12:56:211362 info_fec_pt112.receive_codecs.insert(std::make_pair(
Henrik Boströmb2be3922022-09-02 07:37:081363 inbound_codec_pt112_fec.payload_type, inbound_codec_pt112_fec));
Henrik Boström31c373b2022-09-26 12:56:211364 info_fec_pt112.receivers.emplace_back();
1365 info_fec_pt112.receivers[0].add_ssrc(112);
1366 info_fec_pt112.receivers[0].codec_payload_type =
1367 inbound_codec_pt112_fec.payload_type;
Henrik Boströmb2be3922022-09-02 07:37:081368 pc_->AddVideoChannel("Mid5", "BundledTransport", info_fec_pt112);
1369 stats_->stats_collector()->ClearCachedStatsReport();
1370 report = stats_->GetStatsReport();
1371 codec_stats = report->GetStatsOfType<RTCCodecStats>();
1372 EXPECT_EQ(codec_stats.size(), 3u);
1373}
1374
hbos6ab97ce02016-10-03 21:16:561375TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsMultiple) {
Steve Anton5b387312018-02-03 00:00:201376 const char kAudioTransport[] = "audio";
1377 const char kVideoTransport[] = "video";
1378
1379 pc_->AddVoiceChannel("audio", kAudioTransport);
Tommi19015512022-02-02 10:49:351380
hbos6ab97ce02016-10-03 21:16:561381 std::unique_ptr<CertificateInfo> audio_local_certinfo =
1382 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 13:03:051383 std::vector<std::string>({"(local) audio"}));
Steve Anton5b387312018-02-03 00:00:201384 pc_->SetLocalCertificate(kAudioTransport, audio_local_certinfo->certificate);
hbos6ab97ce02016-10-03 21:16:561385 std::unique_ptr<CertificateInfo> audio_remote_certinfo =
1386 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 13:03:051387 std::vector<std::string>({"(remote) audio"}));
Taylor Brandstetterc3928662018-02-23 21:04:511388 pc_->SetRemoteCertChain(
1389 kAudioTransport,
Benjamin Wright6c6c9df2018-10-25 08:16:261390 audio_remote_certinfo->certificate->GetSSLCertificateChain().Clone());
hbos6ab97ce02016-10-03 21:16:561391
Steve Anton5b387312018-02-03 00:00:201392 pc_->AddVideoChannel("video", kVideoTransport);
hbos6ab97ce02016-10-03 21:16:561393 std::unique_ptr<CertificateInfo> video_local_certinfo =
1394 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 13:03:051395 std::vector<std::string>({"(local) video"}));
Steve Anton5b387312018-02-03 00:00:201396 pc_->SetLocalCertificate(kVideoTransport, video_local_certinfo->certificate);
hbos6ab97ce02016-10-03 21:16:561397 std::unique_ptr<CertificateInfo> video_remote_certinfo =
1398 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 13:03:051399 std::vector<std::string>({"(remote) video"}));
Taylor Brandstetterc3928662018-02-23 21:04:511400 pc_->SetRemoteCertChain(
1401 kVideoTransport,
Benjamin Wright6c6c9df2018-10-25 08:16:261402 video_remote_certinfo->certificate->GetSSLCertificateChain().Clone());
hbos6ab97ce02016-10-03 21:16:561403
Steve Anton5b387312018-02-03 00:00:201404 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos23368e12016-12-21 12:29:171405 ExpectReportContainsCertificateInfo(report, *audio_local_certinfo);
1406 ExpectReportContainsCertificateInfo(report, *audio_remote_certinfo);
1407 ExpectReportContainsCertificateInfo(report, *video_local_certinfo);
1408 ExpectReportContainsCertificateInfo(report, *video_remote_certinfo);
hbos6ab97ce02016-10-03 21:16:561409}
1410
1411TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsChain) {
Steve Anton5b387312018-02-03 00:00:201412 const char kTransportName[] = "transport";
1413
1414 pc_->AddVoiceChannel("audio", kTransportName);
1415
hbos6ab97ce02016-10-03 21:16:561416 std::unique_ptr<CertificateInfo> local_certinfo =
Steve Anton5b387312018-02-03 00:00:201417 CreateFakeCertificateAndInfoFromDers(
1418 {"(local) this", "(local) is", "(local) a", "(local) chain"});
1419 pc_->SetLocalCertificate(kTransportName, local_certinfo->certificate);
1420
hbos6ab97ce02016-10-03 21:16:561421 std::unique_ptr<CertificateInfo> remote_certinfo =
Steve Anton5b387312018-02-03 00:00:201422 CreateFakeCertificateAndInfoFromDers({"(remote) this", "(remote) is",
1423 "(remote) another",
1424 "(remote) chain"});
Taylor Brandstetterc3928662018-02-23 21:04:511425 pc_->SetRemoteCertChain(
Benjamin Wright6c6c9df2018-10-25 08:16:261426 kTransportName,
1427 remote_certinfo->certificate->GetSSLCertificateChain().Clone());
hbos6ab97ce02016-10-03 21:16:561428
Steve Anton5b387312018-02-03 00:00:201429 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos23368e12016-12-21 12:29:171430 ExpectReportContainsCertificateInfo(report, *local_certinfo);
1431 ExpectReportContainsCertificateInfo(report, *remote_certinfo);
hbos6ab97ce02016-10-03 21:16:561432}
1433
Henrik Boström69d23c92022-09-26 12:13:171434TEST_F(RTCStatsCollectorTest, CertificateStatsCache) {
1435 const char kTransportName[] = "transport";
1436 rtc::ScopedFakeClock fake_clock;
1437
1438 pc_->AddVoiceChannel("audio", kTransportName);
1439
1440 // Set local and remote cerificates.
1441 std::unique_ptr<CertificateInfo> initial_local_certinfo =
1442 CreateFakeCertificateAndInfoFromDers({"LocalCertA", "LocalCertB"});
1443 pc_->SetLocalCertificate(kTransportName, initial_local_certinfo->certificate);
1444 std::unique_ptr<CertificateInfo> initial_remote_certinfo =
1445 CreateFakeCertificateAndInfoFromDers({"RemoteCertA", "RemoteCertB"});
1446 pc_->SetRemoteCertChain(
1447 kTransportName,
1448 initial_remote_certinfo->certificate->GetSSLCertificateChain().Clone());
1449 ASSERT_EQ(initial_local_certinfo->fingerprints.size(), 2u);
1450 ASSERT_EQ(initial_remote_certinfo->fingerprints.size(), 2u);
1451
1452 rtc::scoped_refptr<const RTCStatsReport> first_report =
1453 stats_->GetStatsReport();
1454 const auto* first_local_cert0 = GetCertificateStatsFromFingerprint(
1455 first_report, initial_local_certinfo->fingerprints[0]);
1456 const auto* first_local_cert1 = GetCertificateStatsFromFingerprint(
1457 first_report, initial_local_certinfo->fingerprints[1]);
1458 const auto* first_remote_cert0 = GetCertificateStatsFromFingerprint(
1459 first_report, initial_remote_certinfo->fingerprints[0]);
1460 const auto* first_remote_cert1 = GetCertificateStatsFromFingerprint(
1461 first_report, initial_remote_certinfo->fingerprints[1]);
1462 ASSERT_TRUE(first_local_cert0);
1463 ASSERT_TRUE(first_local_cert1);
1464 ASSERT_TRUE(first_remote_cert0);
1465 ASSERT_TRUE(first_remote_cert1);
Philipp Hanckeb81823a2023-01-04 14:17:421466 EXPECT_EQ(first_local_cert0->timestamp().us(), rtc::TimeMicros());
1467 EXPECT_EQ(first_local_cert1->timestamp().us(), rtc::TimeMicros());
1468 EXPECT_EQ(first_remote_cert0->timestamp().us(), rtc::TimeMicros());
1469 EXPECT_EQ(first_remote_cert1->timestamp().us(), rtc::TimeMicros());
Henrik Boström69d23c92022-09-26 12:13:171470
1471 // Replace all certificates.
1472 std::unique_ptr<CertificateInfo> updated_local_certinfo =
1473 CreateFakeCertificateAndInfoFromDers(
1474 {"UpdatedLocalCertA", "UpdatedLocalCertB"});
1475 pc_->SetLocalCertificate(kTransportName, updated_local_certinfo->certificate);
1476 std::unique_ptr<CertificateInfo> updated_remote_certinfo =
1477 CreateFakeCertificateAndInfoFromDers(
1478 {"UpdatedRemoteCertA", "UpdatedRemoteCertB"});
1479 pc_->SetRemoteCertChain(
1480 kTransportName,
1481 updated_remote_certinfo->certificate->GetSSLCertificateChain().Clone());
1482 // This test assumes fingerprints are different for the old and new
1483 // certificates.
1484 EXPECT_NE(initial_local_certinfo->fingerprints,
1485 updated_local_certinfo->fingerprints);
1486 EXPECT_NE(initial_remote_certinfo->fingerprints,
1487 updated_remote_certinfo->fingerprints);
1488
1489 // Advance time to ensure a fresh stats report, but don't clear the
1490 // certificate stats cache.
1491 fake_clock.AdvanceTime(TimeDelta::Seconds(1));
1492 rtc::scoped_refptr<const RTCStatsReport> second_report =
1493 stats_->GetStatsReport();
1494 // We expect to see the same certificates as before due to not clearing the
1495 // certificate cache.
1496 const auto* second_local_cert0 =
1497 second_report->GetAs<RTCCertificateStats>(first_local_cert0->id());
1498 const auto* second_local_cert1 =
1499 second_report->GetAs<RTCCertificateStats>(first_local_cert1->id());
1500 const auto* second_remote_cert0 =
1501 second_report->GetAs<RTCCertificateStats>(first_remote_cert0->id());
1502 const auto* second_remote_cert1 =
1503 second_report->GetAs<RTCCertificateStats>(first_remote_cert1->id());
1504 ASSERT_TRUE(second_local_cert0);
1505 ASSERT_TRUE(second_local_cert1);
1506 ASSERT_TRUE(second_remote_cert0);
1507 ASSERT_TRUE(second_remote_cert1);
1508 // The information in the certificate stats are obsolete.
1509 EXPECT_EQ(*second_local_cert0->fingerprint,
1510 initial_local_certinfo->fingerprints[0]);
1511 EXPECT_EQ(*second_local_cert1->fingerprint,
1512 initial_local_certinfo->fingerprints[1]);
1513 EXPECT_EQ(*second_remote_cert0->fingerprint,
1514 initial_remote_certinfo->fingerprints[0]);
1515 EXPECT_EQ(*second_remote_cert1->fingerprint,
1516 initial_remote_certinfo->fingerprints[1]);
1517 // But timestamps are up-to-date, because this is a fresh stats report.
Philipp Hanckeb81823a2023-01-04 14:17:421518 EXPECT_EQ(second_local_cert0->timestamp().us(), rtc::TimeMicros());
1519 EXPECT_EQ(second_local_cert1->timestamp().us(), rtc::TimeMicros());
1520 EXPECT_EQ(second_remote_cert0->timestamp().us(), rtc::TimeMicros());
1521 EXPECT_EQ(second_remote_cert1->timestamp().us(), rtc::TimeMicros());
Henrik Boström69d23c92022-09-26 12:13:171522 // The updated certificates are not part of the report yet.
1523 EXPECT_FALSE(GetCertificateStatsFromFingerprint(
1524 second_report, updated_local_certinfo->fingerprints[0]));
1525 EXPECT_FALSE(GetCertificateStatsFromFingerprint(
1526 second_report, updated_local_certinfo->fingerprints[1]));
1527 EXPECT_FALSE(GetCertificateStatsFromFingerprint(
1528 second_report, updated_remote_certinfo->fingerprints[0]));
1529 EXPECT_FALSE(GetCertificateStatsFromFingerprint(
1530 second_report, updated_remote_certinfo->fingerprints[1]));
1531
1532 // Clear the cache, including the cached certificates.
1533 stats_->stats_collector()->ClearCachedStatsReport();
1534 rtc::scoped_refptr<const RTCStatsReport> third_report =
1535 stats_->GetStatsReport();
1536 // Now the old certificates stats should be deleted.
1537 EXPECT_FALSE(third_report->Get(first_local_cert0->id()));
1538 EXPECT_FALSE(third_report->Get(first_local_cert1->id()));
1539 EXPECT_FALSE(third_report->Get(first_remote_cert0->id()));
1540 EXPECT_FALSE(third_report->Get(first_remote_cert1->id()));
1541 // And updated certificates exist.
1542 EXPECT_TRUE(GetCertificateStatsFromFingerprint(
1543 third_report, updated_local_certinfo->fingerprints[0]));
1544 EXPECT_TRUE(GetCertificateStatsFromFingerprint(
1545 third_report, updated_local_certinfo->fingerprints[1]));
1546 EXPECT_TRUE(GetCertificateStatsFromFingerprint(
1547 third_report, updated_remote_certinfo->fingerprints[0]));
1548 EXPECT_TRUE(GetCertificateStatsFromFingerprint(
1549 third_report, updated_remote_certinfo->fingerprints[1]));
1550}
1551
Harald Alvestrand928e7a32019-07-31 11:16:451552TEST_F(RTCStatsCollectorTest, CollectTwoRTCDataChannelStatsWithPendingId) {
Philipp Hancke423faa62023-04-18 11:27:301553 // Note: The test assumes data channel IDs are predictable.
1554 // This is not a safe assumption, but in order to make it work for
1555 // the test, we reset the ID allocator at test start.
1556 SctpDataChannel::ResetInternalIdAllocatorForTesting(-1);
Niels Möllere7cc8832022-01-04 14:20:031557 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
Tommifaf33872023-03-16 08:25:291558 data_channel_controller_->weak_ptr(), /*id=*/-1,
1559 DataChannelInterface::kConnecting));
Niels Möllere7cc8832022-01-04 14:20:031560 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
Tommifaf33872023-03-16 08:25:291561 data_channel_controller_->weak_ptr(), /*id=*/-1,
1562 DataChannelInterface::kConnecting));
Harald Alvestrand928e7a32019-07-31 11:16:451563
1564 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Philipp Hancke423faa62023-04-18 11:27:301565 RTCDataChannelStats expected_data_channel0("D0", Timestamp::Zero());
1566 // Default values from MockDataChannel.
1567 expected_data_channel0.label = "MockSctpDataChannel";
1568 expected_data_channel0.protocol = "someProtocol";
1569 expected_data_channel0.state = "connecting";
1570 expected_data_channel0.messages_sent = 0;
1571 expected_data_channel0.bytes_sent = 0;
1572 expected_data_channel0.messages_received = 0;
1573 expected_data_channel0.bytes_received = 0;
1574
1575 ASSERT_TRUE(report->Get(expected_data_channel0.id()));
1576 EXPECT_EQ(
1577 expected_data_channel0,
1578 report->Get(expected_data_channel0.id())->cast_to<RTCDataChannelStats>());
Harald Alvestrand928e7a32019-07-31 11:16:451579}
1580
hboscc555c52016-10-18 19:48:311581TEST_F(RTCStatsCollectorTest, CollectRTCDataChannelStats) {
Harald Alvestrand928e7a32019-07-31 11:16:451582 // Note: The test assumes data channel IDs are predictable.
1583 // This is not a safe assumption, but in order to make it work for
1584 // the test, we reset the ID allocator at test start.
Taylor Brandstetter3a034e12020-07-09 22:32:341585 SctpDataChannel::ResetInternalIdAllocatorForTesting(-1);
Niels Möllere7cc8832022-01-04 14:20:031586 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
Tommifaf33872023-03-16 08:25:291587 data_channel_controller_->weak_ptr(), 0, "MockSctpDataChannel0",
Philipp Hancke423faa62023-04-18 11:27:301588 DataChannelInterface::kConnecting, "proto1", 1, 2, 3, 4));
Philipp Hanckeb81823a2023-01-04 14:17:421589 RTCDataChannelStats expected_data_channel0("D0", Timestamp::Zero());
Taylor Brandstetter3a034e12020-07-09 22:32:341590 expected_data_channel0.label = "MockSctpDataChannel0";
Philipp Hancke423faa62023-04-18 11:27:301591 expected_data_channel0.protocol = "proto1";
Harald Alvestrand10ef8472020-06-05 13:38:511592 expected_data_channel0.data_channel_identifier = 0;
hbosdbb64d82016-12-21 09:57:461593 expected_data_channel0.state = "connecting";
1594 expected_data_channel0.messages_sent = 1;
1595 expected_data_channel0.bytes_sent = 2;
1596 expected_data_channel0.messages_received = 3;
1597 expected_data_channel0.bytes_received = 4;
1598
Niels Möllere7cc8832022-01-04 14:20:031599 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
Tommifaf33872023-03-16 08:25:291600 data_channel_controller_->weak_ptr(), 1, "MockSctpDataChannel1",
Philipp Hancke423faa62023-04-18 11:27:301601 DataChannelInterface::kOpen, "proto2", 5, 6, 7, 8));
Philipp Hanckeb81823a2023-01-04 14:17:421602 RTCDataChannelStats expected_data_channel1("D1", Timestamp::Zero());
Taylor Brandstetter3a034e12020-07-09 22:32:341603 expected_data_channel1.label = "MockSctpDataChannel1";
Philipp Hancke423faa62023-04-18 11:27:301604 expected_data_channel1.protocol = "proto2";
Harald Alvestrand10ef8472020-06-05 13:38:511605 expected_data_channel1.data_channel_identifier = 1;
hbosdbb64d82016-12-21 09:57:461606 expected_data_channel1.state = "open";
1607 expected_data_channel1.messages_sent = 5;
1608 expected_data_channel1.bytes_sent = 6;
1609 expected_data_channel1.messages_received = 7;
1610 expected_data_channel1.bytes_received = 8;
1611
Niels Möllere7cc8832022-01-04 14:20:031612 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
Tommifaf33872023-03-16 08:25:291613 data_channel_controller_->weak_ptr(), 2, "MockSctpDataChannel2",
Philipp Hancke423faa62023-04-18 11:27:301614 DataChannelInterface::kClosing, "proto1", 9, 10, 11, 12));
Philipp Hanckeb81823a2023-01-04 14:17:421615 RTCDataChannelStats expected_data_channel2("D2", Timestamp::Zero());
Taylor Brandstetter3a034e12020-07-09 22:32:341616 expected_data_channel2.label = "MockSctpDataChannel2";
Philipp Hancke423faa62023-04-18 11:27:301617 expected_data_channel2.protocol = "proto1";
Harald Alvestrand10ef8472020-06-05 13:38:511618 expected_data_channel2.data_channel_identifier = 2;
hbosdbb64d82016-12-21 09:57:461619 expected_data_channel2.state = "closing";
1620 expected_data_channel2.messages_sent = 9;
1621 expected_data_channel2.bytes_sent = 10;
1622 expected_data_channel2.messages_received = 11;
1623 expected_data_channel2.bytes_received = 12;
1624
Niels Möllere7cc8832022-01-04 14:20:031625 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
Tommifaf33872023-03-16 08:25:291626 data_channel_controller_->weak_ptr(), 3, "MockSctpDataChannel3",
Philipp Hancke423faa62023-04-18 11:27:301627 DataChannelInterface::kClosed, "proto3", 13, 14, 15, 16));
Philipp Hanckeb81823a2023-01-04 14:17:421628 RTCDataChannelStats expected_data_channel3("D3", Timestamp::Zero());
Taylor Brandstetter3a034e12020-07-09 22:32:341629 expected_data_channel3.label = "MockSctpDataChannel3";
Philipp Hancke423faa62023-04-18 11:27:301630 expected_data_channel3.protocol = "proto3";
Harald Alvestrand10ef8472020-06-05 13:38:511631 expected_data_channel3.data_channel_identifier = 3;
hbosdbb64d82016-12-21 09:57:461632 expected_data_channel3.state = "closed";
1633 expected_data_channel3.messages_sent = 13;
1634 expected_data_channel3.bytes_sent = 14;
1635 expected_data_channel3.messages_received = 15;
1636 expected_data_channel3.bytes_received = 16;
hboscc555c52016-10-18 19:48:311637
Steve Anton5b387312018-02-03 00:00:201638 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1639
hbosdbb64d82016-12-21 09:57:461640 ASSERT_TRUE(report->Get(expected_data_channel0.id()));
Yves Gerey665174f2018-06-19 13:03:051641 EXPECT_EQ(
1642 expected_data_channel0,
1643 report->Get(expected_data_channel0.id())->cast_to<RTCDataChannelStats>());
hbosdbb64d82016-12-21 09:57:461644 ASSERT_TRUE(report->Get(expected_data_channel1.id()));
Yves Gerey665174f2018-06-19 13:03:051645 EXPECT_EQ(
1646 expected_data_channel1,
1647 report->Get(expected_data_channel1.id())->cast_to<RTCDataChannelStats>());
hbosdbb64d82016-12-21 09:57:461648 ASSERT_TRUE(report->Get(expected_data_channel2.id()));
Yves Gerey665174f2018-06-19 13:03:051649 EXPECT_EQ(
1650 expected_data_channel2,
1651 report->Get(expected_data_channel2.id())->cast_to<RTCDataChannelStats>());
hbosdbb64d82016-12-21 09:57:461652 ASSERT_TRUE(report->Get(expected_data_channel3.id()));
Yves Gerey665174f2018-06-19 13:03:051653 EXPECT_EQ(
1654 expected_data_channel3,
1655 report->Get(expected_data_channel3.id())->cast_to<RTCDataChannelStats>());
hboscc555c52016-10-18 19:48:311656}
1657
hbosab9f6e42016-10-07 09:18:471658TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidateStats) {
1659 // Candidates in the first transport stats.
Jonas Oreland0d13bbd2022-03-02 10:17:361660 std::unique_ptr<cricket::Candidate> a_local_host = CreateFakeCandidate(
1661 "1.2.3.4", 5, "a_local_host's protocol", rtc::ADAPTER_TYPE_VPN,
1662 cricket::LOCAL_PORT_TYPE, 0, rtc::ADAPTER_TYPE_ETHERNET);
Philipp Hanckeb81823a2023-01-04 14:17:421663 RTCLocalIceCandidateStats expected_a_local_host("I" + a_local_host->id(),
1664 Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291665 expected_a_local_host.transport_id = "Ta0";
Gary Liu37e489c2017-11-21 18:49:361666 expected_a_local_host.network_type = "vpn";
hbosc42ba322016-12-21 11:31:451667 expected_a_local_host.ip = "1.2.3.4";
Philipp Hanckea9ba4502021-03-22 12:22:541668 expected_a_local_host.address = "1.2.3.4";
hbosc42ba322016-12-21 11:31:451669 expected_a_local_host.port = 5;
1670 expected_a_local_host.protocol = "a_local_host's protocol";
1671 expected_a_local_host.candidate_type = "host";
1672 expected_a_local_host.priority = 0;
Jonas Oreland0d13bbd2022-03-02 10:17:361673 expected_a_local_host.vpn = true;
Henrik Boströmc929ab42023-06-15 13:17:451674 expected_a_local_host.network_adapter_type = "ethernet";
Philipp Hancke0e3cd632022-09-27 08:23:091675 expected_a_local_host.foundation = "foundationIsAString";
1676 expected_a_local_host.username_fragment = "iceusernamefragment";
hbosc42ba322016-12-21 11:31:451677
hbosab9f6e42016-10-07 09:18:471678 std::unique_ptr<cricket::Candidate> a_remote_srflx = CreateFakeCandidate(
Gary Liu37e489c2017-11-21 18:49:361679 "6.7.8.9", 10, "remote_srflx's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
1680 cricket::STUN_PORT_TYPE, 1);
Henrik Boström8dfc90f2022-09-02 07:39:291681 RTCRemoteIceCandidateStats expected_a_remote_srflx("I" + a_remote_srflx->id(),
Philipp Hanckeb81823a2023-01-04 14:17:421682 Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291683 expected_a_remote_srflx.transport_id = "Ta0";
hbosc42ba322016-12-21 11:31:451684 expected_a_remote_srflx.ip = "6.7.8.9";
Philipp Hanckea9ba4502021-03-22 12:22:541685 expected_a_remote_srflx.address = "6.7.8.9";
hbosc42ba322016-12-21 11:31:451686 expected_a_remote_srflx.port = 10;
1687 expected_a_remote_srflx.protocol = "remote_srflx's protocol";
1688 expected_a_remote_srflx.candidate_type = "srflx";
1689 expected_a_remote_srflx.priority = 1;
Philipp Hancke0e3cd632022-09-27 08:23:091690 expected_a_remote_srflx.foundation = "foundationIsAString";
1691 expected_a_remote_srflx.username_fragment = "iceusernamefragment";
hbosc42ba322016-12-21 11:31:451692
hbosab9f6e42016-10-07 09:18:471693 std::unique_ptr<cricket::Candidate> a_local_prflx = CreateFakeCandidate(
Jonas Oreland0d13bbd2022-03-02 10:17:361694 "11.12.13.14", 15, "a_local_prflx's protocol",
1695 rtc::ADAPTER_TYPE_CELLULAR_2G, cricket::PRFLX_PORT_TYPE, 2);
Henrik Boström8dfc90f2022-09-02 07:39:291696 RTCLocalIceCandidateStats expected_a_local_prflx("I" + a_local_prflx->id(),
Philipp Hanckeb81823a2023-01-04 14:17:421697 Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291698 expected_a_local_prflx.transport_id = "Ta0";
Gary Liu37e489c2017-11-21 18:49:361699 expected_a_local_prflx.network_type = "cellular";
hbosc42ba322016-12-21 11:31:451700 expected_a_local_prflx.ip = "11.12.13.14";
Philipp Hanckea9ba4502021-03-22 12:22:541701 expected_a_local_prflx.address = "11.12.13.14";
hbosc42ba322016-12-21 11:31:451702 expected_a_local_prflx.port = 15;
1703 expected_a_local_prflx.protocol = "a_local_prflx's protocol";
1704 expected_a_local_prflx.candidate_type = "prflx";
1705 expected_a_local_prflx.priority = 2;
Jonas Oreland0d13bbd2022-03-02 10:17:361706 expected_a_local_prflx.vpn = false;
Henrik Boströmc929ab42023-06-15 13:17:451707 expected_a_local_prflx.network_adapter_type = "cellular2g";
Philipp Hancke0e3cd632022-09-27 08:23:091708 expected_a_local_prflx.foundation = "foundationIsAString";
1709 expected_a_local_prflx.username_fragment = "iceusernamefragment";
hbosc42ba322016-12-21 11:31:451710
hbosab9f6e42016-10-07 09:18:471711 std::unique_ptr<cricket::Candidate> a_remote_relay = CreateFakeCandidate(
Gary Liu37e489c2017-11-21 18:49:361712 "16.17.18.19", 20, "a_remote_relay's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
1713 cricket::RELAY_PORT_TYPE, 3);
Henrik Boström8dfc90f2022-09-02 07:39:291714 RTCRemoteIceCandidateStats expected_a_remote_relay("I" + a_remote_relay->id(),
Philipp Hanckeb81823a2023-01-04 14:17:421715 Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291716 expected_a_remote_relay.transport_id = "Ta0";
hbosc42ba322016-12-21 11:31:451717 expected_a_remote_relay.ip = "16.17.18.19";
Philipp Hanckea9ba4502021-03-22 12:22:541718 expected_a_remote_relay.address = "16.17.18.19";
hbosc42ba322016-12-21 11:31:451719 expected_a_remote_relay.port = 20;
1720 expected_a_remote_relay.protocol = "a_remote_relay's protocol";
1721 expected_a_remote_relay.candidate_type = "relay";
1722 expected_a_remote_relay.priority = 3;
Philipp Hancke0e3cd632022-09-27 08:23:091723 expected_a_remote_relay.foundation = "foundationIsAString";
1724 expected_a_remote_relay.username_fragment = "iceusernamefragment";
hbosc42ba322016-12-21 11:31:451725
Philipp Hancke95513752018-09-27 12:40:081726 std::unique_ptr<cricket::Candidate> a_local_relay = CreateFakeCandidate(
1727 "16.17.18.19", 21, "a_local_relay's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
1728 cricket::RELAY_PORT_TYPE, 1);
1729 a_local_relay->set_relay_protocol("tcp");
Philipp Hancke05b29c72022-02-02 11:06:151730 a_local_relay->set_url("turn:url1");
Philipp Hancke95513752018-09-27 12:40:081731
Henrik Boström8dfc90f2022-09-02 07:39:291732 RTCLocalIceCandidateStats expected_a_local_relay("I" + a_local_relay->id(),
Philipp Hanckeb81823a2023-01-04 14:17:421733 Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291734 expected_a_local_relay.transport_id = "Ta0";
Philipp Hanckefbd52c02021-11-10 22:02:171735 expected_a_local_relay.network_type = "unknown";
Philipp Hancke95513752018-09-27 12:40:081736 expected_a_local_relay.ip = "16.17.18.19";
Philipp Hanckea9ba4502021-03-22 12:22:541737 expected_a_local_relay.address = "16.17.18.19";
Philipp Hancke95513752018-09-27 12:40:081738 expected_a_local_relay.port = 21;
1739 expected_a_local_relay.protocol = "a_local_relay's protocol";
1740 expected_a_local_relay.relay_protocol = "tcp";
1741 expected_a_local_relay.candidate_type = "relay";
1742 expected_a_local_relay.priority = 1;
Philipp Hancke05b29c72022-02-02 11:06:151743 expected_a_local_relay.url = "turn:url1";
Jonas Oreland0d13bbd2022-03-02 10:17:361744 expected_a_local_relay.vpn = false;
Henrik Boströmc929ab42023-06-15 13:17:451745 expected_a_local_relay.network_adapter_type = "unknown";
Philipp Hancke0e3cd632022-09-27 08:23:091746 expected_a_local_relay.foundation = "foundationIsAString";
1747 expected_a_local_relay.username_fragment = "iceusernamefragment";
Philipp Hancke95513752018-09-27 12:40:081748
Philipp Hancke21c4b1e2021-11-11 06:45:591749 std::unique_ptr<cricket::Candidate> a_local_relay_prflx = CreateFakeCandidate(
1750 "11.12.13.20", 22, "a_local_relay_prflx's protocol",
1751 rtc::ADAPTER_TYPE_UNKNOWN, cricket::PRFLX_PORT_TYPE, 1);
1752 a_local_relay_prflx->set_relay_protocol("udp");
1753
1754 RTCLocalIceCandidateStats expected_a_local_relay_prflx(
Philipp Hanckeb81823a2023-01-04 14:17:421755 "I" + a_local_relay_prflx->id(), Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291756 expected_a_local_relay_prflx.transport_id = "Ta0";
Philipp Hancke21c4b1e2021-11-11 06:45:591757 expected_a_local_relay_prflx.network_type = "unknown";
1758 expected_a_local_relay_prflx.ip = "11.12.13.20";
1759 expected_a_local_relay_prflx.address = "11.12.13.20";
1760 expected_a_local_relay_prflx.port = 22;
1761 expected_a_local_relay_prflx.protocol = "a_local_relay_prflx's protocol";
1762 expected_a_local_relay_prflx.relay_protocol = "udp";
1763 expected_a_local_relay_prflx.candidate_type = "prflx";
1764 expected_a_local_relay_prflx.priority = 1;
Jonas Oreland0d13bbd2022-03-02 10:17:361765 expected_a_local_relay_prflx.vpn = false;
Henrik Boströmc929ab42023-06-15 13:17:451766 expected_a_local_relay_prflx.network_adapter_type = "unknown";
Philipp Hancke0e3cd632022-09-27 08:23:091767 expected_a_local_relay_prflx.foundation = "foundationIsAString";
1768 expected_a_local_relay_prflx.username_fragment = "iceusernamefragment";
Philipp Hancke21c4b1e2021-11-11 06:45:591769
Philipp Hancke6e57ca22022-06-09 13:58:181770 // A non-paired local candidate.
1771 std::unique_ptr<cricket::Candidate> a_local_host_not_paired =
1772 CreateFakeCandidate("1.2.3.4", 4404, "a_local_host_not_paired's protocol",
1773 rtc::ADAPTER_TYPE_VPN, cricket::LOCAL_PORT_TYPE, 0,
1774 rtc::ADAPTER_TYPE_ETHERNET);
1775 RTCLocalIceCandidateStats expected_a_local_host_not_paired(
Philipp Hanckeb81823a2023-01-04 14:17:421776 "I" + a_local_host_not_paired->id(), Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291777 expected_a_local_host_not_paired.transport_id = "Ta0";
Philipp Hancke6e57ca22022-06-09 13:58:181778 expected_a_local_host_not_paired.network_type = "vpn";
1779 expected_a_local_host_not_paired.ip = "1.2.3.4";
1780 expected_a_local_host_not_paired.address = "1.2.3.4";
1781 expected_a_local_host_not_paired.port = 4404;
1782 expected_a_local_host_not_paired.protocol =
1783 "a_local_host_not_paired's protocol";
1784 expected_a_local_host_not_paired.candidate_type = "host";
1785 expected_a_local_host_not_paired.priority = 0;
1786 expected_a_local_host_not_paired.vpn = true;
Henrik Boströmc929ab42023-06-15 13:17:451787 expected_a_local_host_not_paired.network_adapter_type = "ethernet";
Philipp Hancke0e3cd632022-09-27 08:23:091788 expected_a_local_host_not_paired.foundation = "foundationIsAString";
1789 expected_a_local_host_not_paired.username_fragment = "iceusernamefragment";
Philipp Hancke6e57ca22022-06-09 13:58:181790
hbosab9f6e42016-10-07 09:18:471791 // Candidates in the second transport stats.
Gary Liu37e489c2017-11-21 18:49:361792 std::unique_ptr<cricket::Candidate> b_local =
1793 CreateFakeCandidate("42.42.42.42", 42, "b_local's protocol",
1794 rtc::ADAPTER_TYPE_WIFI, cricket::LOCAL_PORT_TYPE, 42);
Philipp Hanckeb81823a2023-01-04 14:17:421795 RTCLocalIceCandidateStats expected_b_local("I" + b_local->id(),
1796 Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291797 expected_b_local.transport_id = "Tb0";
Gary Liu37e489c2017-11-21 18:49:361798 expected_b_local.network_type = "wifi";
hbosc42ba322016-12-21 11:31:451799 expected_b_local.ip = "42.42.42.42";
Philipp Hanckea9ba4502021-03-22 12:22:541800 expected_b_local.address = "42.42.42.42";
hbosc42ba322016-12-21 11:31:451801 expected_b_local.port = 42;
1802 expected_b_local.protocol = "b_local's protocol";
1803 expected_b_local.candidate_type = "host";
1804 expected_b_local.priority = 42;
Jonas Oreland0d13bbd2022-03-02 10:17:361805 expected_b_local.vpn = false;
Henrik Boströmc929ab42023-06-15 13:17:451806 expected_b_local.network_adapter_type = "wifi";
Philipp Hancke0e3cd632022-09-27 08:23:091807 expected_b_local.foundation = "foundationIsAString";
1808 expected_b_local.username_fragment = "iceusernamefragment";
hbosc42ba322016-12-21 11:31:451809
hbosab9f6e42016-10-07 09:18:471810 std::unique_ptr<cricket::Candidate> b_remote = CreateFakeCandidate(
Gary Liu37e489c2017-11-21 18:49:361811 "42.42.42.42", 42, "b_remote's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
1812 cricket::LOCAL_PORT_TYPE, 42);
Philipp Hanckeb81823a2023-01-04 14:17:421813 RTCRemoteIceCandidateStats expected_b_remote("I" + b_remote->id(),
1814 Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291815 expected_b_remote.transport_id = "Tb0";
hbosc42ba322016-12-21 11:31:451816 expected_b_remote.ip = "42.42.42.42";
Philipp Hanckea9ba4502021-03-22 12:22:541817 expected_b_remote.address = "42.42.42.42";
hbosc42ba322016-12-21 11:31:451818 expected_b_remote.port = 42;
1819 expected_b_remote.protocol = "b_remote's protocol";
1820 expected_b_remote.candidate_type = "host";
1821 expected_b_remote.priority = 42;
Philipp Hancke0e3cd632022-09-27 08:23:091822 expected_b_remote.foundation = "foundationIsAString";
1823 expected_b_remote.username_fragment = "iceusernamefragment";
hbosab9f6e42016-10-07 09:18:471824
Philipp Hancke95513752018-09-27 12:40:081825 // Add candidate pairs to connection.
hbosab9f6e42016-10-07 09:18:471826 cricket::TransportChannelStats a_transport_channel_stats;
Jonas Oreland149dc722019-08-28 06:10:271827 a_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
hbosab9f6e42016-10-07 09:18:471828 cricket::ConnectionInfo());
Jonas Oreland149dc722019-08-28 06:10:271829 a_transport_channel_stats.ice_transport_stats.connection_infos[0]
1830 .local_candidate = *a_local_host.get();
1831 a_transport_channel_stats.ice_transport_stats.connection_infos[0]
1832 .remote_candidate = *a_remote_srflx.get();
1833 a_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
hbosab9f6e42016-10-07 09:18:471834 cricket::ConnectionInfo());
Jonas Oreland149dc722019-08-28 06:10:271835 a_transport_channel_stats.ice_transport_stats.connection_infos[1]
1836 .local_candidate = *a_local_prflx.get();
1837 a_transport_channel_stats.ice_transport_stats.connection_infos[1]
1838 .remote_candidate = *a_remote_relay.get();
1839 a_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
Philipp Hancke95513752018-09-27 12:40:081840 cricket::ConnectionInfo());
Jonas Oreland149dc722019-08-28 06:10:271841 a_transport_channel_stats.ice_transport_stats.connection_infos[2]
1842 .local_candidate = *a_local_relay.get();
1843 a_transport_channel_stats.ice_transport_stats.connection_infos[2]
1844 .remote_candidate = *a_remote_relay.get();
Philipp Hancke21c4b1e2021-11-11 06:45:591845 a_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
1846 cricket::ConnectionInfo());
1847 a_transport_channel_stats.ice_transport_stats.connection_infos[3]
1848 .local_candidate = *a_local_relay_prflx.get();
1849 a_transport_channel_stats.ice_transport_stats.connection_infos[3]
1850 .remote_candidate = *a_remote_relay.get();
Philipp Hancke6e57ca22022-06-09 13:58:181851 a_transport_channel_stats.ice_transport_stats.candidate_stats_list.push_back(
1852 cricket::CandidateStats(*a_local_host_not_paired.get()));
Steve Anton5b387312018-02-03 00:00:201853
1854 pc_->AddVoiceChannel("audio", "a");
1855 pc_->SetTransportStats("a", a_transport_channel_stats);
hbosab9f6e42016-10-07 09:18:471856
1857 cricket::TransportChannelStats b_transport_channel_stats;
Jonas Oreland149dc722019-08-28 06:10:271858 b_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
hbosab9f6e42016-10-07 09:18:471859 cricket::ConnectionInfo());
Jonas Oreland149dc722019-08-28 06:10:271860 b_transport_channel_stats.ice_transport_stats.connection_infos[0]
1861 .local_candidate = *b_local.get();
1862 b_transport_channel_stats.ice_transport_stats.connection_infos[0]
1863 .remote_candidate = *b_remote.get();
hbosab9f6e42016-10-07 09:18:471864
Steve Anton5b387312018-02-03 00:00:201865 pc_->AddVideoChannel("video", "b");
1866 pc_->SetTransportStats("b", b_transport_channel_stats);
hbosab9f6e42016-10-07 09:18:471867
Steve Anton5b387312018-02-03 00:00:201868 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbosc42ba322016-12-21 11:31:451869
hbosb4e426e2017-01-02 17:59:311870 ASSERT_TRUE(report->Get(expected_a_local_host.id()));
Yves Gerey665174f2018-06-19 13:03:051871 EXPECT_EQ(expected_a_local_host, report->Get(expected_a_local_host.id())
1872 ->cast_to<RTCLocalIceCandidateStats>());
Philipp Hancke6e57ca22022-06-09 13:58:181873
1874 ASSERT_TRUE(report->Get(expected_a_local_host_not_paired.id()));
1875 EXPECT_EQ(expected_a_local_host_not_paired,
1876 report->Get(expected_a_local_host_not_paired.id())
1877 ->cast_to<RTCLocalIceCandidateStats>());
1878
hbosb4e426e2017-01-02 17:59:311879 ASSERT_TRUE(report->Get(expected_a_remote_srflx.id()));
hbosc42ba322016-12-21 11:31:451880 EXPECT_EQ(expected_a_remote_srflx,
Yves Gerey665174f2018-06-19 13:03:051881 report->Get(expected_a_remote_srflx.id())
1882 ->cast_to<RTCRemoteIceCandidateStats>());
hbosb4e426e2017-01-02 17:59:311883 ASSERT_TRUE(report->Get(expected_a_local_prflx.id()));
Yves Gerey665174f2018-06-19 13:03:051884 EXPECT_EQ(expected_a_local_prflx, report->Get(expected_a_local_prflx.id())
1885 ->cast_to<RTCLocalIceCandidateStats>());
hbosb4e426e2017-01-02 17:59:311886 ASSERT_TRUE(report->Get(expected_a_remote_relay.id()));
hbosc42ba322016-12-21 11:31:451887 EXPECT_EQ(expected_a_remote_relay,
Yves Gerey665174f2018-06-19 13:03:051888 report->Get(expected_a_remote_relay.id())
1889 ->cast_to<RTCRemoteIceCandidateStats>());
Philipp Hanckefbd52c02021-11-10 22:02:171890 ASSERT_TRUE(report->Get(expected_a_local_relay.id()));
1891 EXPECT_EQ(expected_a_local_relay, report->Get(expected_a_local_relay.id())
1892 ->cast_to<RTCLocalIceCandidateStats>());
Philipp Hancke21c4b1e2021-11-11 06:45:591893 ASSERT_TRUE(report->Get(expected_a_local_relay_prflx.id()));
1894 EXPECT_EQ(expected_a_local_relay_prflx,
1895 report->Get(expected_a_local_relay_prflx.id())
1896 ->cast_to<RTCLocalIceCandidateStats>());
hbosb4e426e2017-01-02 17:59:311897 ASSERT_TRUE(report->Get(expected_b_local.id()));
Yves Gerey665174f2018-06-19 13:03:051898 EXPECT_EQ(
1899 expected_b_local,
1900 report->Get(expected_b_local.id())->cast_to<RTCLocalIceCandidateStats>());
hbosb4e426e2017-01-02 17:59:311901 ASSERT_TRUE(report->Get(expected_b_remote.id()));
Yves Gerey665174f2018-06-19 13:03:051902 EXPECT_EQ(expected_b_remote, report->Get(expected_b_remote.id())
1903 ->cast_to<RTCRemoteIceCandidateStats>());
Henrik Boström8dfc90f2022-09-02 07:39:291904 EXPECT_TRUE(report->Get("Ta0"));
1905 EXPECT_TRUE(report->Get("Tb0"));
hbosab9f6e42016-10-07 09:18:471906}
1907
hbosc47a0c32016-10-11 21:54:491908TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidatePairStats) {
Steve Anton5b387312018-02-03 00:00:201909 const char kTransportName[] = "transport";
hbos338f78a2017-02-07 14:41:211910
Gary Liu37e489c2017-11-21 18:49:361911 std::unique_ptr<cricket::Candidate> local_candidate =
1912 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
1913 cricket::LOCAL_PORT_TYPE, 42);
Philipp Hancke0e3cd632022-09-27 08:23:091914 local_candidate->set_username("local_iceusernamefragment");
1915
hbosc47a0c32016-10-11 21:54:491916 std::unique_ptr<cricket::Candidate> remote_candidate = CreateFakeCandidate(
Gary Liu37e489c2017-11-21 18:49:361917 "42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_UNKNOWN,
Philipp Hancke0e3cd632022-09-27 08:23:091918 cricket::STUN_PORT_TYPE, 42);
1919 remote_candidate->set_related_address(rtc::SocketAddress("192.168.2.1", 43));
1920 remote_candidate->set_username("remote_iceusernamefragment");
hbosc47a0c32016-10-11 21:54:491921
hbosc47a0c32016-10-11 21:54:491922 cricket::ConnectionInfo connection_info;
hbos338f78a2017-02-07 14:41:211923 connection_info.best_connection = false;
hbosc47a0c32016-10-11 21:54:491924 connection_info.local_candidate = *local_candidate.get();
1925 connection_info.remote_candidate = *remote_candidate.get();
1926 connection_info.writable = true;
Taylor Brandstetter79326ea2021-09-28 22:09:531927 connection_info.sent_discarded_packets = 3;
1928 connection_info.sent_total_packets = 10;
1929 connection_info.packets_received = 51;
1930 connection_info.sent_discarded_bytes = 7;
hbosc47a0c32016-10-11 21:54:491931 connection_info.sent_total_bytes = 42;
1932 connection_info.recv_total_bytes = 1234;
hbosbf8d3e52017-02-28 14:34:471933 connection_info.total_round_trip_time_ms = 0;
Danil Chapovalov66cadcc2018-06-19 14:47:431934 connection_info.current_round_trip_time_ms = absl::nullopt;
hbosd82f5122016-12-09 12:12:391935 connection_info.recv_ping_requests = 2020;
Henrik Boström839439a2022-09-06 09:16:361936 connection_info.sent_ping_requests_total = 2222;
hbose448dd52016-12-12 09:22:531937 connection_info.sent_ping_requests_before_first_response = 2000;
hbosc47a0c32016-10-11 21:54:491938 connection_info.recv_ping_responses = 4321;
1939 connection_info.sent_ping_responses = 1000;
hbos06495bc2017-01-02 16:08:181940 connection_info.state = cricket::IceCandidatePairState::IN_PROGRESS;
1941 connection_info.priority = 5555;
hbos92eaec62017-02-27 09:38:081942 connection_info.nominated = false;
Philipp Hancke0487c572022-11-01 16:03:011943 connection_info.last_data_received = Timestamp::Millis(2500);
1944 connection_info.last_data_sent = Timestamp::Millis(5200);
hbosc47a0c32016-10-11 21:54:491945
1946 cricket::TransportChannelStats transport_channel_stats;
hbos0583b282016-11-30 09:50:141947 transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
Jonas Oreland149dc722019-08-28 06:10:271948 transport_channel_stats.ice_transport_stats.connection_infos.push_back(
1949 connection_info);
hbosc47a0c32016-10-11 21:54:491950
Steve Anton5b387312018-02-03 00:00:201951 pc_->AddVideoChannel("video", kTransportName);
1952 pc_->SetTransportStats(kTransportName, transport_channel_stats);
hbosc47a0c32016-10-11 21:54:491953
Steve Anton5b387312018-02-03 00:00:201954 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos0583b282016-11-30 09:50:141955
Henrik Boström8dfc90f2022-09-02 07:39:291956 RTCIceCandidatePairStats expected_pair(
1957 "CP" + local_candidate->id() + "_" + remote_candidate->id(),
Philipp Hanckeb81823a2023-01-04 14:17:421958 report->timestamp());
hbos0583b282016-11-30 09:50:141959 expected_pair.transport_id =
Henrik Boström8dfc90f2022-09-02 07:39:291960 "Ttransport" + rtc::ToString(cricket::ICE_CANDIDATE_COMPONENT_RTP);
1961 expected_pair.local_candidate_id = "I" + local_candidate->id();
1962 expected_pair.remote_candidate_id = "I" + remote_candidate->id();
Henrik Boströmc929ab42023-06-15 13:17:451963 expected_pair.state = "in-progress";
hbos06495bc2017-01-02 16:08:181964 expected_pair.priority = 5555;
hbos92eaec62017-02-27 09:38:081965 expected_pair.nominated = false;
hbos0583b282016-11-30 09:50:141966 expected_pair.writable = true;
Taylor Brandstetter79326ea2021-09-28 22:09:531967 expected_pair.packets_sent = 7;
1968 expected_pair.packets_received = 51;
1969 expected_pair.packets_discarded_on_send = 3;
hbos0583b282016-11-30 09:50:141970 expected_pair.bytes_sent = 42;
1971 expected_pair.bytes_received = 1234;
Taylor Brandstetter79326ea2021-09-28 22:09:531972 expected_pair.bytes_discarded_on_send = 7;
hbosbf8d3e52017-02-28 14:34:471973 expected_pair.total_round_trip_time = 0.0;
hbosd82f5122016-12-09 12:12:391974 expected_pair.requests_received = 2020;
Henrik Boström839439a2022-09-06 09:16:361975 expected_pair.requests_sent = 2222;
hbos0583b282016-11-30 09:50:141976 expected_pair.responses_received = 4321;
1977 expected_pair.responses_sent = 1000;
Henrik Boström839439a2022-09-06 09:16:361978 expected_pair.consent_requests_sent = (2222 - 2000);
Philipp Hancke0487c572022-11-01 16:03:011979 expected_pair.last_packet_received_timestamp = 2500;
1980 expected_pair.last_packet_sent_timestamp = 5200;
1981
Artem Titovcfea2182021-08-09 23:22:311982 // `expected_pair.current_round_trip_time` should be undefined because the
hbosbf8d3e52017-02-28 14:34:471983 // current RTT is not set.
Artem Titovcfea2182021-08-09 23:22:311984 // `expected_pair.available_[outgoing/incoming]_bitrate` should be undefined
hbos338f78a2017-02-07 14:41:211985 // because is is not the current pair.
hbos0583b282016-11-30 09:50:141986
hbosdbb64d82016-12-21 09:57:461987 ASSERT_TRUE(report->Get(expected_pair.id()));
hbos0583b282016-11-30 09:50:141988 EXPECT_EQ(
1989 expected_pair,
1990 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
hbosb4e426e2017-01-02 17:59:311991 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
hbos0583b282016-11-30 09:50:141992
hbos92eaec62017-02-27 09:38:081993 // Set nominated and "GetStats" again.
Jonas Oreland149dc722019-08-28 06:10:271994 transport_channel_stats.ice_transport_stats.connection_infos[0].nominated =
1995 true;
Steve Anton5b387312018-02-03 00:00:201996 pc_->SetTransportStats(kTransportName, transport_channel_stats);
1997 report = stats_->GetFreshStatsReport();
hbos92eaec62017-02-27 09:38:081998 expected_pair.nominated = true;
1999 ASSERT_TRUE(report->Get(expected_pair.id()));
2000 EXPECT_EQ(
2001 expected_pair,
2002 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
2003 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
2004
hbosbf8d3e52017-02-28 14:34:472005 // Set round trip times and "GetStats" again.
Jonas Oreland149dc722019-08-28 06:10:272006 transport_channel_stats.ice_transport_stats.connection_infos[0]
2007 .total_round_trip_time_ms = 7331;
2008 transport_channel_stats.ice_transport_stats.connection_infos[0]
2009 .current_round_trip_time_ms = 1337;
Steve Anton5b387312018-02-03 00:00:202010 pc_->SetTransportStats(kTransportName, transport_channel_stats);
2011 report = stats_->GetFreshStatsReport();
hbosbf8d3e52017-02-28 14:34:472012 expected_pair.total_round_trip_time = 7.331;
2013 expected_pair.current_round_trip_time = 1.337;
2014 ASSERT_TRUE(report->Get(expected_pair.id()));
2015 EXPECT_EQ(
2016 expected_pair,
2017 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
2018 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
2019
hbos338f78a2017-02-07 14:41:212020 // Make pair the current pair, clear bandwidth and "GetStats" again.
Jonas Oreland149dc722019-08-28 06:10:272021 transport_channel_stats.ice_transport_stats.connection_infos[0]
2022 .best_connection = true;
Steve Anton5b387312018-02-03 00:00:202023 pc_->SetTransportStats(kTransportName, transport_channel_stats);
2024 report = stats_->GetFreshStatsReport();
hbos338f78a2017-02-07 14:41:212025 // |expected_pair.available_[outgoing/incoming]_bitrate| should still be
2026 // undefined because bandwidth is not set.
2027 ASSERT_TRUE(report->Get(expected_pair.id()));
2028 EXPECT_EQ(
2029 expected_pair,
2030 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
2031 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
2032
2033 // Set bandwidth and "GetStats" again.
Harald Alvestranda6544372023-11-13 09:33:562034 Call::Stats call_stats;
stefanf79ade12017-06-02 13:44:032035 const int kSendBandwidth = 888;
2036 call_stats.send_bandwidth_bps = kSendBandwidth;
2037 const int kRecvBandwidth = 999;
2038 call_stats.recv_bandwidth_bps = kRecvBandwidth;
Steve Anton5b387312018-02-03 00:00:202039 pc_->SetCallStats(call_stats);
2040 report = stats_->GetFreshStatsReport();
stefanf79ade12017-06-02 13:44:032041 expected_pair.available_outgoing_bitrate = kSendBandwidth;
2042 expected_pair.available_incoming_bitrate = kRecvBandwidth;
hbos338f78a2017-02-07 14:41:212043 ASSERT_TRUE(report->Get(expected_pair.id()));
2044 EXPECT_EQ(
2045 expected_pair,
2046 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
2047 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
2048
hbosc42ba322016-12-21 11:31:452049 RTCLocalIceCandidateStats expected_local_candidate(
Philipp Hanckeb81823a2023-01-04 14:17:422050 *expected_pair.local_candidate_id, report->timestamp());
hbosb4e426e2017-01-02 17:59:312051 expected_local_candidate.transport_id = *expected_pair.transport_id;
Gary Liu37e489c2017-11-21 18:49:362052 expected_local_candidate.network_type = "wifi";
hbosc42ba322016-12-21 11:31:452053 expected_local_candidate.ip = "42.42.42.42";
Philipp Hanckea9ba4502021-03-22 12:22:542054 expected_local_candidate.address = "42.42.42.42";
hbosc42ba322016-12-21 11:31:452055 expected_local_candidate.port = 42;
2056 expected_local_candidate.protocol = "protocol";
2057 expected_local_candidate.candidate_type = "host";
2058 expected_local_candidate.priority = 42;
Philipp Hancke0e3cd632022-09-27 08:23:092059 expected_local_candidate.foundation = "foundationIsAString";
2060 expected_local_candidate.username_fragment = "local_iceusernamefragment";
Jonas Oreland0d13bbd2022-03-02 10:17:362061 expected_local_candidate.vpn = false;
Henrik Boströmc929ab42023-06-15 13:17:452062 expected_local_candidate.network_adapter_type = "wifi";
hbosc42ba322016-12-21 11:31:452063 ASSERT_TRUE(report->Get(expected_local_candidate.id()));
2064 EXPECT_EQ(expected_local_candidate,
Yves Gerey665174f2018-06-19 13:03:052065 report->Get(expected_local_candidate.id())
2066 ->cast_to<RTCLocalIceCandidateStats>());
hbosc42ba322016-12-21 11:31:452067
2068 RTCRemoteIceCandidateStats expected_remote_candidate(
Philipp Hanckeb81823a2023-01-04 14:17:422069 *expected_pair.remote_candidate_id, report->timestamp());
hbosb4e426e2017-01-02 17:59:312070 expected_remote_candidate.transport_id = *expected_pair.transport_id;
hbosc42ba322016-12-21 11:31:452071 expected_remote_candidate.ip = "42.42.42.42";
Philipp Hanckea9ba4502021-03-22 12:22:542072 expected_remote_candidate.address = "42.42.42.42";
hbosc42ba322016-12-21 11:31:452073 expected_remote_candidate.port = 42;
2074 expected_remote_candidate.protocol = "protocol";
Philipp Hancke0e3cd632022-09-27 08:23:092075 expected_remote_candidate.candidate_type = "srflx";
hbosc42ba322016-12-21 11:31:452076 expected_remote_candidate.priority = 42;
Philipp Hancke0e3cd632022-09-27 08:23:092077 expected_remote_candidate.foundation = "foundationIsAString";
2078 expected_remote_candidate.username_fragment = "remote_iceusernamefragment";
2079 expected_remote_candidate.related_address = "192.168.2.1";
2080 expected_remote_candidate.related_port = 43;
hbosc42ba322016-12-21 11:31:452081 ASSERT_TRUE(report->Get(expected_remote_candidate.id()));
2082 EXPECT_EQ(expected_remote_candidate,
Yves Gerey665174f2018-06-19 13:03:052083 report->Get(expected_remote_candidate.id())
2084 ->cast_to<RTCRemoteIceCandidateStats>());
hbosc47a0c32016-10-11 21:54:492085}
2086
hbosd565b732016-08-30 21:04:352087TEST_F(RTCStatsCollectorTest, CollectRTCPeerConnectionStats) {
hbosd565b732016-08-30 21:04:352088 {
Steve Anton5b387312018-02-03 00:00:202089 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Philipp Hanckeb81823a2023-01-04 14:17:422090 RTCPeerConnectionStats expected("P", report->timestamp());
hbos82ebe022016-11-14 09:41:092091 expected.data_channels_opened = 0;
2092 expected.data_channels_closed = 0;
Henrik Boström8dfc90f2022-09-02 07:39:292093 ASSERT_TRUE(report->Get("P"));
2094 EXPECT_EQ(expected, report->Get("P")->cast_to<RTCPeerConnectionStats>());
hbosd565b732016-08-30 21:04:352095 }
2096
Tommi55f72802023-03-27 10:39:332097 FakeDataChannelController controller(pc_->network_thread());
Taylor Brandstetter3a034e12020-07-09 22:32:342098 rtc::scoped_refptr<SctpDataChannel> dummy_channel_a = SctpDataChannel::Create(
Tommie9aa8672023-03-20 13:43:092099 controller.weak_ptr(), "DummyChannelA", false, InternalDataChannelInit(),
Tomas Gunnarsson7d3cfbf2020-06-15 11:47:422100 rtc::Thread::Current(), rtc::Thread::Current());
Taylor Brandstetter3a034e12020-07-09 22:32:342101 rtc::scoped_refptr<SctpDataChannel> dummy_channel_b = SctpDataChannel::Create(
Tommie9aa8672023-03-20 13:43:092102 controller.weak_ptr(), "DummyChannelB", false, InternalDataChannelInit(),
Tomas Gunnarsson7d3cfbf2020-06-15 11:47:422103 rtc::Thread::Current(), rtc::Thread::Current());
hbosd565b732016-08-30 21:04:352104
Tommid2afbaf2023-03-02 09:51:162105 stats_->stats_collector()->OnSctpDataChannelStateChanged(
Tommi56548982023-03-27 16:07:342106 dummy_channel_a->internal_id(), DataChannelInterface::DataState::kOpen);
hbos82ebe022016-11-14 09:41:092107 // Closing a channel that is not opened should not affect the counts.
Tommid2afbaf2023-03-02 09:51:162108 stats_->stats_collector()->OnSctpDataChannelStateChanged(
Tommi56548982023-03-27 16:07:342109 dummy_channel_b->internal_id(), DataChannelInterface::DataState::kClosed);
hbos82ebe022016-11-14 09:41:092110
hbosd565b732016-08-30 21:04:352111 {
Steve Anton5b387312018-02-03 00:00:202112 rtc::scoped_refptr<const RTCStatsReport> report =
2113 stats_->GetFreshStatsReport();
Philipp Hanckeb81823a2023-01-04 14:17:422114 RTCPeerConnectionStats expected("P", report->timestamp());
hbos82ebe022016-11-14 09:41:092115 expected.data_channels_opened = 1;
2116 expected.data_channels_closed = 0;
Henrik Boström8dfc90f2022-09-02 07:39:292117 ASSERT_TRUE(report->Get("P"));
2118 EXPECT_EQ(expected, report->Get("P")->cast_to<RTCPeerConnectionStats>());
hbos82ebe022016-11-14 09:41:092119 }
2120
Tommid2afbaf2023-03-02 09:51:162121 stats_->stats_collector()->OnSctpDataChannelStateChanged(
Tommi56548982023-03-27 16:07:342122 dummy_channel_b->internal_id(), DataChannelInterface::DataState::kOpen);
Tommid2afbaf2023-03-02 09:51:162123 stats_->stats_collector()->OnSctpDataChannelStateChanged(
Tommi56548982023-03-27 16:07:342124 dummy_channel_b->internal_id(), DataChannelInterface::DataState::kClosed);
hbos82ebe022016-11-14 09:41:092125
2126 {
Steve Anton5b387312018-02-03 00:00:202127 rtc::scoped_refptr<const RTCStatsReport> report =
2128 stats_->GetFreshStatsReport();
Philipp Hanckeb81823a2023-01-04 14:17:422129 RTCPeerConnectionStats expected("P", report->timestamp());
hbos82ebe022016-11-14 09:41:092130 expected.data_channels_opened = 2;
2131 expected.data_channels_closed = 1;
Henrik Boström8dfc90f2022-09-02 07:39:292132 ASSERT_TRUE(report->Get("P"));
2133 EXPECT_EQ(expected, report->Get("P")->cast_to<RTCPeerConnectionStats>());
hbosd565b732016-08-30 21:04:352134 }
hbos5bf9def2017-03-20 10:14:142135
2136 // Re-opening a data channel (or opening a new data channel that is re-using
2137 // the same address in memory) should increase the opened count.
Tommid2afbaf2023-03-02 09:51:162138 stats_->stats_collector()->OnSctpDataChannelStateChanged(
Tommi56548982023-03-27 16:07:342139 dummy_channel_b->internal_id(), DataChannelInterface::DataState::kOpen);
hbos5bf9def2017-03-20 10:14:142140
2141 {
Steve Anton5b387312018-02-03 00:00:202142 rtc::scoped_refptr<const RTCStatsReport> report =
2143 stats_->GetFreshStatsReport();
Philipp Hanckeb81823a2023-01-04 14:17:422144 RTCPeerConnectionStats expected("P", report->timestamp());
hbos5bf9def2017-03-20 10:14:142145 expected.data_channels_opened = 3;
2146 expected.data_channels_closed = 1;
Henrik Boström8dfc90f2022-09-02 07:39:292147 ASSERT_TRUE(report->Get("P"));
2148 EXPECT_EQ(expected, report->Get("P")->cast_to<RTCPeerConnectionStats>());
hbos5bf9def2017-03-20 10:14:142149 }
2150
Tommid2afbaf2023-03-02 09:51:162151 stats_->stats_collector()->OnSctpDataChannelStateChanged(
Tommi56548982023-03-27 16:07:342152 dummy_channel_a->internal_id(), DataChannelInterface::DataState::kClosed);
Tommid2afbaf2023-03-02 09:51:162153 stats_->stats_collector()->OnSctpDataChannelStateChanged(
Tommi56548982023-03-27 16:07:342154 dummy_channel_b->internal_id(), DataChannelInterface::DataState::kClosed);
hbos5bf9def2017-03-20 10:14:142155
2156 {
Steve Anton5b387312018-02-03 00:00:202157 rtc::scoped_refptr<const RTCStatsReport> report =
2158 stats_->GetFreshStatsReport();
Philipp Hanckeb81823a2023-01-04 14:17:422159 RTCPeerConnectionStats expected("P", report->timestamp());
hbos5bf9def2017-03-20 10:14:142160 expected.data_channels_opened = 3;
2161 expected.data_channels_closed = 3;
Henrik Boström8dfc90f2022-09-02 07:39:292162 ASSERT_TRUE(report->Get("P"));
2163 EXPECT_EQ(expected, report->Get("P")->cast_to<RTCPeerConnectionStats>());
hbos5bf9def2017-03-20 10:14:142164 }
hbosd565b732016-08-30 21:04:352165}
2166
Philipp Hancke1f98b462023-03-07 08:53:592167TEST_F(RTCStatsCollectorTest, CollectRTCInboundRtpStreamStats_Audio) {
hboseeafe942016-11-01 10:00:172168 cricket::VoiceMediaInfo voice_media_info;
hbos0adb8282016-11-23 10:32:062169
hboseeafe942016-11-01 10:00:172170 voice_media_info.receivers.push_back(cricket::VoiceReceiverInfo());
2171 voice_media_info.receivers[0].local_stats.push_back(
2172 cricket::SsrcReceiverInfo());
2173 voice_media_info.receivers[0].local_stats[0].ssrc = 1;
Harald Alvestrand719487e2017-12-13 11:26:042174 voice_media_info.receivers[0].packets_lost = -1; // Signed per RFC3550
Minyue Li28a2c632021-07-07 13:53:382175 voice_media_info.receivers[0].packets_discarded = 7788;
Philipp Hancke6a7bf102023-04-21 17:32:422176 voice_media_info.receivers[0].packets_received = 2;
Jakob Ivarssone54914a2021-07-01 09:16:052177 voice_media_info.receivers[0].nacks_sent = 5;
Ivo Creusen8d8ffdb2019-04-30 07:45:212178 voice_media_info.receivers[0].fec_packets_discarded = 5566;
2179 voice_media_info.receivers[0].fec_packets_received = 6677;
Philipp Hancke6a7bf102023-04-21 17:32:422180 voice_media_info.receivers[0].payload_bytes_received = 3;
2181 voice_media_info.receivers[0].header_and_padding_bytes_received = 4;
Oskar Sundbomcbc71b22017-11-16 09:56:072182 voice_media_info.receivers[0].codec_payload_type = 42;
hboseeafe942016-11-01 10:00:172183 voice_media_info.receivers[0].jitter_ms = 4500;
Eldar Rello4e5bc9f2020-07-06 11:18:072184 voice_media_info.receivers[0].jitter_buffer_delay_seconds = 1.0;
Ivo Creusen11fdb082022-07-04 12:16:392185 voice_media_info.receivers[0].jitter_buffer_target_delay_seconds = 1.1;
Ivo Creusen1a84b562022-07-19 14:33:102186 voice_media_info.receivers[0].jitter_buffer_minimum_delay_seconds = 0.999;
Eldar Rello4e5bc9f2020-07-06 11:18:072187 voice_media_info.receivers[0].jitter_buffer_emitted_count = 2;
2188 voice_media_info.receivers[0].total_samples_received = 3;
2189 voice_media_info.receivers[0].concealed_samples = 4;
2190 voice_media_info.receivers[0].silent_concealed_samples = 5;
2191 voice_media_info.receivers[0].concealment_events = 6;
2192 voice_media_info.receivers[0].inserted_samples_for_deceleration = 7;
2193 voice_media_info.receivers[0].removed_samples_for_acceleration = 8;
Philipp Hanckeaa83cc72020-10-27 08:50:362194 voice_media_info.receivers[0].audio_level = 14442; // [0,32767]
Eldar Rello4e5bc9f2020-07-06 11:18:072195 voice_media_info.receivers[0].total_output_energy = 10.0;
2196 voice_media_info.receivers[0].total_output_duration = 11.0;
Henrik Boström2fb83072022-10-06 11:37:112197 voice_media_info.receivers[0].jitter_buffer_flushes = 7;
2198 voice_media_info.receivers[0].delayed_packet_outage_samples = 15;
2199 voice_media_info.receivers[0].relative_packet_arrival_delay_seconds = 16;
2200 voice_media_info.receivers[0].interruption_count = 7788;
2201 voice_media_info.receivers[0].total_interruption_duration_ms = 778899;
Danil Chapovalov54e95bc2023-06-02 12:54:452202 voice_media_info.receivers[0].last_packet_received = absl::nullopt;
hbos0adb8282016-11-23 10:32:062203
2204 RtpCodecParameters codec_parameters;
2205 codec_parameters.payload_type = 42;
deadbeefe702b302017-02-04 20:09:012206 codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
2207 codec_parameters.name = "dummy";
Oskar Sundbomcbc71b22017-11-16 09:56:072208 codec_parameters.clock_rate = 0;
hbos0adb8282016-11-23 10:32:062209 voice_media_info.receive_codecs.insert(
2210 std::make_pair(codec_parameters.payload_type, codec_parameters));
2211
Harald Alvestrand2f553702023-03-07 10:10:032212 auto voice_media_channels =
Tommi19015512022-02-02 10:49:352213 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Henrik Boström5b3541f2018-03-19 12:52:562214 stats_->SetupRemoteTrackAndReceiver(
2215 cricket::MEDIA_TYPE_AUDIO, "RemoteAudioTrackID", "RemoteStreamId", 1);
hboseeafe942016-11-01 10:00:172216
Fredrik Hernqvist828de802023-01-19 14:04:542217 // Needed for playoutId to be populated.
2218 pc_->SetAudioDeviceStats(AudioDeviceModule::Stats());
2219 pc_->GetTransceiversInternal()[0]->internal()->set_current_direction(
2220 RtpTransceiverDirection::kSendRecv);
2221
Steve Anton5b387312018-02-03 00:00:202222 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hboseeafe942016-11-01 10:00:172223
Philipp Hancke1f98b462023-03-07 08:53:592224 RTCInboundRtpStreamStats expected_audio("ITTransportName1A1",
Philipp Hanckeb81823a2023-01-04 14:17:422225 report->timestamp());
hbos3443bb72017-02-07 14:28:112226 expected_audio.ssrc = 1;
Philipp Hancke3bc01662018-08-28 12:55:032227 expected_audio.kind = "audio";
Henrik Boströma6c7d5c2022-06-16 14:55:312228 expected_audio.track_identifier = "RemoteAudioTrackID";
Henrik Boström1ab61882022-06-16 15:07:332229 expected_audio.mid = "AudioMid";
Henrik Boström8dfc90f2022-09-02 07:39:292230 expected_audio.transport_id = "TTransportName1";
2231 expected_audio.codec_id = "CITTransportName1_42";
hboseeafe942016-11-01 10:00:172232 expected_audio.packets_received = 2;
Jakob Ivarssone54914a2021-07-01 09:16:052233 expected_audio.nack_count = 5;
Ivo Creusen8d8ffdb2019-04-30 07:45:212234 expected_audio.fec_packets_discarded = 5566;
2235 expected_audio.fec_packets_received = 6677;
hboseeafe942016-11-01 10:00:172236 expected_audio.bytes_received = 3;
Niels Möllerac0a4cb2019-10-09 13:01:332237 expected_audio.header_bytes_received = 4;
Harald Alvestrand719487e2017-12-13 11:26:042238 expected_audio.packets_lost = -1;
Minyue Li28a2c632021-07-07 13:53:382239 expected_audio.packets_discarded = 7788;
Artem Titovcfea2182021-08-09 23:22:312240 // `expected_audio.last_packet_received_timestamp` should be undefined.
hboseeafe942016-11-01 10:00:172241 expected_audio.jitter = 4.5;
Eldar Rello4e5bc9f2020-07-06 11:18:072242 expected_audio.jitter_buffer_delay = 1.0;
Ivo Creusen11fdb082022-07-04 12:16:392243 expected_audio.jitter_buffer_target_delay = 1.1;
Ivo Creusen1a84b562022-07-19 14:33:102244 expected_audio.jitter_buffer_minimum_delay = 0.999;
Eldar Rello4e5bc9f2020-07-06 11:18:072245 expected_audio.jitter_buffer_emitted_count = 2;
2246 expected_audio.total_samples_received = 3;
2247 expected_audio.concealed_samples = 4;
2248 expected_audio.silent_concealed_samples = 5;
2249 expected_audio.concealment_events = 6;
2250 expected_audio.inserted_samples_for_deceleration = 7;
2251 expected_audio.removed_samples_for_acceleration = 8;
Philipp Hanckeaa83cc72020-10-27 08:50:362252 expected_audio.audio_level = 14442.0 / 32767.0; // [0,1]
Eldar Rello4e5bc9f2020-07-06 11:18:072253 expected_audio.total_audio_energy = 10.0;
2254 expected_audio.total_samples_duration = 11.0;
Henrik Boström2fb83072022-10-06 11:37:112255 expected_audio.jitter_buffer_flushes = 7;
2256 expected_audio.delayed_packet_outage_samples = 15;
2257 expected_audio.relative_packet_arrival_delay = 16;
2258 expected_audio.interruption_count = 7788;
2259 expected_audio.total_interruption_duration = 778.899;
Fredrik Hernqvist828de802023-01-19 14:04:542260 expected_audio.playout_id = "AP";
Eldar Rello4e5bc9f2020-07-06 11:18:072261
nissec8ee8822017-01-18 15:20:552262 ASSERT_TRUE(report->Get(expected_audio.id()));
hbosa51d4f32017-02-16 13:34:482263 EXPECT_EQ(
Philipp Hancke1f98b462023-03-07 08:53:592264 report->Get(expected_audio.id())->cast_to<RTCInboundRtpStreamStats>(),
hbosa51d4f32017-02-16 13:34:482265 expected_audio);
Henrik Boström01738c62019-04-15 15:32:002266
2267 // Set previously undefined values and "GetStats" again.
Danil Chapovalov54e95bc2023-06-02 12:54:452268 voice_media_info.receivers[0].last_packet_received = Timestamp::Seconds(3);
Alessio Bazzicac366d512021-03-22 14:36:532269 expected_audio.last_packet_received_timestamp = 3000.0;
Åsa Perssonfcf79cc2019-10-22 13:23:442270 voice_media_info.receivers[0].estimated_playout_ntp_timestamp_ms = 4567;
2271 expected_audio.estimated_playout_timestamp = 4567;
Harald Alvestrand2f553702023-03-07 10:10:032272 voice_media_channels.first->SetStats(voice_media_info);
2273 voice_media_channels.second->SetStats(voice_media_info);
Henrik Boström01738c62019-04-15 15:32:002274
2275 report = stats_->GetFreshStatsReport();
2276
2277 ASSERT_TRUE(report->Get(expected_audio.id()));
2278 EXPECT_EQ(
Philipp Hancke1f98b462023-03-07 08:53:592279 report->Get(expected_audio.id())->cast_to<RTCInboundRtpStreamStats>(),
Henrik Boström01738c62019-04-15 15:32:002280 expected_audio);
hbos84abeb12017-01-16 14:16:442281 EXPECT_TRUE(report->Get(*expected_audio.transport_id));
2282 EXPECT_TRUE(report->Get(*expected_audio.codec_id));
hboseeafe942016-11-01 10:00:172283}
2284
Philipp Hancke1f98b462023-03-07 08:53:592285TEST_F(RTCStatsCollectorTest, CollectRTCInboundRtpStreamStats_Audio_PlayoutId) {
Fredrik Hernqvist828de802023-01-19 14:04:542286 cricket::VoiceMediaInfo voice_media_info;
2287
2288 voice_media_info.receivers.push_back(cricket::VoiceReceiverInfo());
2289 voice_media_info.receivers[0].local_stats.push_back(
2290 cricket::SsrcReceiverInfo());
2291 voice_media_info.receivers[0].local_stats[0].ssrc = 1;
2292
2293 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
2294 stats_->SetupRemoteTrackAndReceiver(
2295 cricket::MEDIA_TYPE_AUDIO, "RemoteAudioTrackID", "RemoteStreamId", 1);
2296 // Needed for playoutId to be populated.
2297 pc_->SetAudioDeviceStats(AudioDeviceModule::Stats());
2298
2299 {
2300 // We do not expect a playout id when only sending.
2301 pc_->GetTransceiversInternal()[0]->internal()->set_current_direction(
2302 RtpTransceiverDirection::kSendOnly);
2303 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
2304 ASSERT_TRUE(report->Get("ITTransportName1A1"));
2305 auto stats =
Philipp Hancke1f98b462023-03-07 08:53:592306 report->Get("ITTransportName1A1")->cast_to<RTCInboundRtpStreamStats>();
Henrik Boströmed1d0842024-01-19 10:27:312307 ASSERT_FALSE(stats.playout_id.has_value());
Fredrik Hernqvist828de802023-01-19 14:04:542308 }
2309 {
2310 // We do expect a playout id when receiving.
2311 pc_->GetTransceiversInternal()[0]->internal()->set_current_direction(
2312 RtpTransceiverDirection::kRecvOnly);
2313 rtc::scoped_refptr<const RTCStatsReport> report =
2314 stats_->GetFreshStatsReport();
2315 ASSERT_TRUE(report->Get("ITTransportName1A1"));
2316 auto stats =
Philipp Hancke1f98b462023-03-07 08:53:592317 report->Get("ITTransportName1A1")->cast_to<RTCInboundRtpStreamStats>();
Henrik Boströmed1d0842024-01-19 10:27:312318 ASSERT_TRUE(stats.playout_id.has_value());
Fredrik Hernqvist828de802023-01-19 14:04:542319 EXPECT_EQ(*stats.playout_id, "AP");
2320 }
2321}
2322
Philipp Hancke1f98b462023-03-07 08:53:592323TEST_F(RTCStatsCollectorTest, CollectRTCInboundRtpStreamStats_Video) {
hboseeafe942016-11-01 10:00:172324 cricket::VideoMediaInfo video_media_info;
hbos0adb8282016-11-23 10:32:062325
hboseeafe942016-11-01 10:00:172326 video_media_info.receivers.push_back(cricket::VideoReceiverInfo());
2327 video_media_info.receivers[0].local_stats.push_back(
2328 cricket::SsrcReceiverInfo());
2329 video_media_info.receivers[0].local_stats[0].ssrc = 1;
Philipp Hancke6a7bf102023-04-21 17:32:422330 video_media_info.receivers[0].packets_received = 2;
hbos02cd4d62016-12-09 12:19:442331 video_media_info.receivers[0].packets_lost = 42;
Philipp Hancke6a7bf102023-04-21 17:32:422332 video_media_info.receivers[0].payload_bytes_received = 3;
2333 video_media_info.receivers[0].header_and_padding_bytes_received = 12;
Oskar Sundbomcbc71b22017-11-16 09:56:072334 video_media_info.receivers[0].codec_payload_type = 42;
hbos820f5782016-11-22 11:16:502335 video_media_info.receivers[0].firs_sent = 5;
2336 video_media_info.receivers[0].plis_sent = 6;
2337 video_media_info.receivers[0].nacks_sent = 7;
Eldar Rello4e5bc9f2020-07-06 11:18:072338 video_media_info.receivers[0].frames_received = 8;
2339 video_media_info.receivers[0].frames_decoded = 9;
Rasmus Brandt2efae772019-06-27 12:29:342340 video_media_info.receivers[0].key_frames_decoded = 3;
Eldar Rello4e5bc9f2020-07-06 11:18:072341 video_media_info.receivers[0].frames_dropped = 13;
Danil Chapovalov66cadcc2018-06-19 14:47:432342 video_media_info.receivers[0].qp_sum = absl::nullopt;
Harald Alvestranda6544372023-11-13 09:33:562343 video_media_info.receivers[0].total_decode_time = TimeDelta::Seconds(9);
2344 video_media_info.receivers[0].total_processing_delay = TimeDelta::Millis(600);
2345 video_media_info.receivers[0].total_assembly_time = TimeDelta::Millis(500);
Philipp Hancke0359ba22022-05-05 13:55:362346 video_media_info.receivers[0].frames_assembled_from_multiple_packets = 23;
Johannes Kron00376e12019-11-25 09:25:422347 video_media_info.receivers[0].total_inter_frame_delay = 0.123;
2348 video_media_info.receivers[0].total_squared_inter_frame_delay = 0.00456;
Henrik Boströmc57a28c2022-10-06 09:59:052349 video_media_info.receivers[0].pause_count = 2;
2350 video_media_info.receivers[0].total_pauses_duration_ms = 10000;
2351 video_media_info.receivers[0].freeze_count = 3;
2352 video_media_info.receivers[0].total_freezes_duration_ms = 1000;
Di Wu (RP Room Eng)8af6b492021-02-20 01:34:222353 video_media_info.receivers[0].jitter_ms = 1199;
Byoungchan Lee899b29e2021-06-29 13:09:182354 video_media_info.receivers[0].jitter_buffer_delay_seconds = 3.456;
Ivo Creusen11fdb082022-07-04 12:16:392355 video_media_info.receivers[0].jitter_buffer_target_delay_seconds = 1.1;
Ivo Creusen1a84b562022-07-19 14:33:102356 video_media_info.receivers[0].jitter_buffer_minimum_delay_seconds = 0.999;
Byoungchan Lee899b29e2021-06-29 13:09:182357 video_media_info.receivers[0].jitter_buffer_emitted_count = 13;
Danil Chapovalov54e95bc2023-06-02 12:54:452358 video_media_info.receivers[0].last_packet_received = absl::nullopt;
Henrik Boström2e069262019-04-09 11:59:312359 video_media_info.receivers[0].content_type = VideoContentType::UNSPECIFIED;
Åsa Perssonfcf79cc2019-10-22 13:23:442360 video_media_info.receivers[0].estimated_playout_ntp_timestamp_ms =
2361 absl::nullopt;
Philipp Hancke656817c2023-06-22 09:41:352362 video_media_info.receivers[0].decoder_implementation_name = absl::nullopt;
Philipp Hancke6fb8d1a2022-05-30 10:37:042363 video_media_info.receivers[0].min_playout_delay_ms = 50;
Evan Shrubsole13c0be42022-10-31 11:03:102364 video_media_info.receivers[0].power_efficient_decoder = false;
Philipp Hanckef78d1f22023-04-25 08:23:472365 video_media_info.receivers[0].retransmitted_packets_received = 17;
2366 video_media_info.receivers[0].retransmitted_bytes_received = 62;
Philipp Hancke17e8a5c2023-06-21 11:53:412367 video_media_info.receivers[0].fec_packets_received = 32;
2368 video_media_info.receivers[0].fec_bytes_received = 54;
Philipp Hancke9b82b2f2023-07-28 10:27:132369 video_media_info.receivers[0].ssrc_groups.push_back(
2370 {cricket::kFidSsrcGroupSemantics, {1, 4404}});
Philipp Hanckee2e04512023-08-04 09:12:462371 video_media_info.receivers[0].ssrc_groups.push_back(
2372 {cricket::kFecFrSsrcGroupSemantics, {1, 5505}});
hbos0adb8282016-11-23 10:32:062373
Philipp Hancke3719a0c2022-07-04 16:24:462374 // Note: these two values intentionally differ,
2375 // only the decoded one should show up.
Philipp Hancke6a7bf102023-04-21 17:32:422376 video_media_info.receivers[0].framerate_received = 15;
Philipp Hancke3719a0c2022-07-04 16:24:462377 video_media_info.receivers[0].framerate_decoded = 5;
2378
hbos0adb8282016-11-23 10:32:062379 RtpCodecParameters codec_parameters;
2380 codec_parameters.payload_type = 42;
Philipp Hancke3719a0c2022-07-04 16:24:462381 codec_parameters.kind = cricket::MEDIA_TYPE_VIDEO;
deadbeefe702b302017-02-04 20:09:012382 codec_parameters.name = "dummy";
Oskar Sundbomcbc71b22017-11-16 09:56:072383 codec_parameters.clock_rate = 0;
hbos0adb8282016-11-23 10:32:062384 video_media_info.receive_codecs.insert(
2385 std::make_pair(codec_parameters.payload_type, codec_parameters));
2386
Harald Alvestrand2f553702023-03-07 10:10:032387 auto video_media_channels =
Tommi19015512022-02-02 10:49:352388 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström5b3541f2018-03-19 12:52:562389 stats_->SetupRemoteTrackAndReceiver(
2390 cricket::MEDIA_TYPE_VIDEO, "RemoteVideoTrackID", "RemoteStreamId", 1);
hboseeafe942016-11-01 10:00:172391
Steve Anton5b387312018-02-03 00:00:202392 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hboseeafe942016-11-01 10:00:172393
Philipp Hancke1f98b462023-03-07 08:53:592394 RTCInboundRtpStreamStats expected_video("ITTransportName1V1",
Philipp Hanckeb81823a2023-01-04 14:17:422395 report->timestamp());
hbos3443bb72017-02-07 14:28:112396 expected_video.ssrc = 1;
Philipp Hancke3bc01662018-08-28 12:55:032397 expected_video.kind = "video";
Henrik Boströma6c7d5c2022-06-16 14:55:312398 expected_video.track_identifier = "RemoteVideoTrackID";
Henrik Boström1ab61882022-06-16 15:07:332399 expected_video.mid = "VideoMid";
Henrik Boström8dfc90f2022-09-02 07:39:292400 expected_video.transport_id = "TTransportName1";
2401 expected_video.codec_id = "CITTransportName1_42";
hbos820f5782016-11-22 11:16:502402 expected_video.fir_count = 5;
2403 expected_video.pli_count = 6;
2404 expected_video.nack_count = 7;
2405 expected_video.packets_received = 2;
2406 expected_video.bytes_received = 3;
Niels Möllerac0a4cb2019-10-09 13:01:332407 expected_video.header_bytes_received = 12;
hbos02cd4d62016-12-09 12:19:442408 expected_video.packets_lost = 42;
Eldar Rello4e5bc9f2020-07-06 11:18:072409 expected_video.frames_received = 8;
2410 expected_video.frames_decoded = 9;
Rasmus Brandt2efae772019-06-27 12:29:342411 expected_video.key_frames_decoded = 3;
Eldar Rello4e5bc9f2020-07-06 11:18:072412 expected_video.frames_dropped = 13;
Artem Titovcfea2182021-08-09 23:22:312413 // `expected_video.qp_sum` should be undefined.
Johannes Kronbfd343b2019-07-01 08:07:502414 expected_video.total_decode_time = 9.0;
Philipp Hanckea16a6a62022-04-25 10:21:302415 expected_video.total_processing_delay = 0.6;
Philipp Hancke0359ba22022-05-05 13:55:362416 expected_video.total_assembly_time = 0.5;
2417 expected_video.frames_assembled_from_multiple_packets = 23;
Johannes Kron00376e12019-11-25 09:25:422418 expected_video.total_inter_frame_delay = 0.123;
2419 expected_video.total_squared_inter_frame_delay = 0.00456;
Henrik Boströmc57a28c2022-10-06 09:59:052420 expected_video.pause_count = 2;
2421 expected_video.total_pauses_duration = 10;
2422 expected_video.freeze_count = 3;
2423 expected_video.total_freezes_duration = 1;
Di Wu (RP Room Eng)8af6b492021-02-20 01:34:222424 expected_video.jitter = 1.199;
Byoungchan Lee899b29e2021-06-29 13:09:182425 expected_video.jitter_buffer_delay = 3.456;
Ivo Creusen11fdb082022-07-04 12:16:392426 expected_video.jitter_buffer_target_delay = 1.1;
Ivo Creusen1a84b562022-07-19 14:33:102427 expected_video.jitter_buffer_minimum_delay = 0.999;
Byoungchan Lee899b29e2021-06-29 13:09:182428 expected_video.jitter_buffer_emitted_count = 13;
Artem Titovcfea2182021-08-09 23:22:312429 // `expected_video.last_packet_received_timestamp` should be undefined.
2430 // `expected_video.content_type` should be undefined.
2431 // `expected_video.decoder_implementation` should be undefined.
Philipp Hancke6fb8d1a2022-05-30 10:37:042432 expected_video.min_playout_delay = 0.05;
Philipp Hancke3719a0c2022-07-04 16:24:462433 expected_video.frames_per_second = 5;
Evan Shrubsole13c0be42022-10-31 11:03:102434 expected_video.power_efficient_decoder = false;
Philipp Hanckef78d1f22023-04-25 08:23:472435 expected_video.retransmitted_packets_received = 17;
2436 expected_video.retransmitted_bytes_received = 62;
Philipp Hancke17e8a5c2023-06-21 11:53:412437 expected_video.fec_packets_received = 32;
2438 expected_video.fec_bytes_received = 54;
Philipp Hancke9b82b2f2023-07-28 10:27:132439 expected_video.rtx_ssrc = 4404;
Philipp Hanckee2e04512023-08-04 09:12:462440 expected_video.fec_ssrc = 5505;
hboseeafe942016-11-01 10:00:172441
nissec8ee8822017-01-18 15:20:552442 ASSERT_TRUE(report->Get(expected_video.id()));
hbosa51d4f32017-02-16 13:34:482443 EXPECT_EQ(
Philipp Hancke1f98b462023-03-07 08:53:592444 report->Get(expected_video.id())->cast_to<RTCInboundRtpStreamStats>(),
hbosa51d4f32017-02-16 13:34:482445 expected_video);
hboseeafe942016-11-01 10:00:172446
hbosa51d4f32017-02-16 13:34:482447 // Set previously undefined values and "GetStats" again.
Oskar Sundbomcbc71b22017-11-16 09:56:072448 video_media_info.receivers[0].qp_sum = 9;
hbosa51d4f32017-02-16 13:34:482449 expected_video.qp_sum = 9;
Danil Chapovalov54e95bc2023-06-02 12:54:452450 video_media_info.receivers[0].last_packet_received = Timestamp::Seconds(1);
Alessio Bazzica5cf8c2c2021-03-24 07:51:262451 expected_video.last_packet_received_timestamp = 1000.0;
Henrik Boström2e069262019-04-09 11:59:312452 video_media_info.receivers[0].content_type = VideoContentType::SCREENSHARE;
2453 expected_video.content_type = "screenshare";
Åsa Perssonfcf79cc2019-10-22 13:23:442454 video_media_info.receivers[0].estimated_playout_ntp_timestamp_ms = 1234;
2455 expected_video.estimated_playout_timestamp = 1234;
Henrik Boström6b430862019-08-16 11:09:512456 video_media_info.receivers[0].decoder_implementation_name = "libfoodecoder";
2457 expected_video.decoder_implementation = "libfoodecoder";
Evan Shrubsole13c0be42022-10-31 11:03:102458 video_media_info.receivers[0].power_efficient_decoder = true;
2459 expected_video.power_efficient_decoder = true;
Harald Alvestrand2f553702023-03-07 10:10:032460 video_media_channels.first->SetStats(video_media_info);
2461 video_media_channels.second->SetStats(video_media_info);
hbosa51d4f32017-02-16 13:34:482462
Steve Anton5b387312018-02-03 00:00:202463 report = stats_->GetFreshStatsReport();
hbosa51d4f32017-02-16 13:34:482464
2465 ASSERT_TRUE(report->Get(expected_video.id()));
2466 EXPECT_EQ(
Philipp Hancke1f98b462023-03-07 08:53:592467 report->Get(expected_video.id())->cast_to<RTCInboundRtpStreamStats>(),
hbosa51d4f32017-02-16 13:34:482468 expected_video);
hbos84abeb12017-01-16 14:16:442469 EXPECT_TRUE(report->Get(*expected_video.transport_id));
hbosa51d4f32017-02-16 13:34:482470 EXPECT_TRUE(report->Get(*expected_video.codec_id));
hboseeafe942016-11-01 10:00:172471}
2472
Fredrik Hernqvistefbe7532023-01-13 15:42:362473TEST_F(RTCStatsCollectorTest, CollectRTCAudioPlayoutStats) {
2474 AudioDeviceModule::Stats audio_device_stats;
2475 audio_device_stats.synthesized_samples_duration_s = 1;
2476 audio_device_stats.synthesized_samples_events = 2;
2477 audio_device_stats.total_samples_count = 3;
2478 audio_device_stats.total_samples_duration_s = 4;
2479 audio_device_stats.total_playout_delay_s = 5;
2480 pc_->SetAudioDeviceStats(audio_device_stats);
2481
Philipp Hanckec5d92182023-12-12 08:22:232482 pc_->AddVoiceChannel("AudioMid", "TransportName", {});
2483 stats_->SetupRemoteTrackAndReceiver(
2484 cricket::MEDIA_TYPE_AUDIO, "RemoteAudioTrackID", "RemoteStreamId", 1);
2485
Fredrik Hernqvistefbe7532023-01-13 15:42:362486 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
2487 auto stats_of_track_type = report->GetStatsOfType<RTCAudioPlayoutStats>();
2488 ASSERT_EQ(1U, stats_of_track_type.size());
2489
2490 RTCAudioPlayoutStats expected_stats("AP", report->timestamp());
Fredrik Hernqvist5adc2b62023-01-25 12:49:162491 expected_stats.kind = "audio";
Fredrik Hernqvistefbe7532023-01-13 15:42:362492 expected_stats.synthesized_samples_duration = 1;
2493 expected_stats.synthesized_samples_events = 2;
2494 expected_stats.total_samples_count = 3;
2495 expected_stats.total_samples_duration = 4;
2496 expected_stats.total_playout_delay = 5;
2497
2498 ASSERT_TRUE(report->Get(expected_stats.id()));
2499 EXPECT_EQ(report->Get(expected_stats.id())->cast_to<RTCAudioPlayoutStats>(),
2500 expected_stats);
2501}
2502
Henrik Boströmc5f8f802022-10-19 15:50:092503TEST_F(RTCStatsCollectorTest, CollectGoogTimingFrameInfo) {
2504 cricket::VideoMediaInfo video_media_info;
2505
2506 video_media_info.receivers.push_back(cricket::VideoReceiverInfo());
2507 video_media_info.receivers[0].local_stats.push_back(
2508 cricket::SsrcReceiverInfo());
2509 video_media_info.receivers[0].local_stats[0].ssrc = 1;
2510 TimingFrameInfo timing_frame_info;
2511 timing_frame_info.rtp_timestamp = 1;
2512 timing_frame_info.capture_time_ms = 2;
2513 timing_frame_info.encode_start_ms = 3;
2514 timing_frame_info.encode_finish_ms = 4;
2515 timing_frame_info.packetization_finish_ms = 5;
2516 timing_frame_info.pacer_exit_ms = 6;
2517 timing_frame_info.network_timestamp_ms = 7;
2518 timing_frame_info.network2_timestamp_ms = 8;
2519 timing_frame_info.receive_start_ms = 9;
2520 timing_frame_info.receive_finish_ms = 10;
2521 timing_frame_info.decode_start_ms = 11;
2522 timing_frame_info.decode_finish_ms = 12;
2523 timing_frame_info.render_time_ms = 13;
2524 timing_frame_info.flags = 14;
2525 video_media_info.receivers[0].timing_frame_info = timing_frame_info;
2526
2527 pc_->AddVideoChannel("Mid0", "Transport0", video_media_info);
2528 stats_->SetupRemoteTrackAndReceiver(
2529 cricket::MEDIA_TYPE_VIDEO, "RemoteVideoTrackID", "RemoteStreamId", 1);
2530
2531 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Philipp Hancke1f98b462023-03-07 08:53:592532 auto inbound_rtps = report->GetStatsOfType<RTCInboundRtpStreamStats>();
Henrik Boströmc5f8f802022-10-19 15:50:092533 ASSERT_EQ(inbound_rtps.size(), 1u);
Henrik Boströmed1d0842024-01-19 10:27:312534 ASSERT_TRUE(inbound_rtps[0]->goog_timing_frame_info.has_value());
Henrik Boströmc5f8f802022-10-19 15:50:092535 EXPECT_EQ(*inbound_rtps[0]->goog_timing_frame_info,
2536 "1,2,3,4,5,6,7,8,9,10,11,12,13,1,0");
2537}
2538
Philipp Hancke1f98b462023-03-07 08:53:592539TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRtpStreamStats_Audio) {
hbos6ded1902016-11-01 08:50:462540 cricket::VoiceMediaInfo voice_media_info;
hbos0adb8282016-11-23 10:32:062541
hbos6ded1902016-11-01 08:50:462542 voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
2543 voice_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
2544 voice_media_info.senders[0].local_stats[0].ssrc = 1;
2545 voice_media_info.senders[0].packets_sent = 2;
Henrik Boströmaebba7b2022-10-26 14:53:032546 voice_media_info.senders[0].total_packet_send_delay = TimeDelta::Seconds(1);
Henrik Boströmcf96e0f2019-04-17 11:51:532547 voice_media_info.senders[0].retransmitted_packets_sent = 20;
Niels Möllerac0a4cb2019-10-09 13:01:332548 voice_media_info.senders[0].payload_bytes_sent = 3;
2549 voice_media_info.senders[0].header_and_padding_bytes_sent = 12;
Henrik Boströmcf96e0f2019-04-17 11:51:532550 voice_media_info.senders[0].retransmitted_bytes_sent = 30;
Philipp Hancke6a7bf102023-04-21 17:32:422551 voice_media_info.senders[0].nacks_received = 31;
Jakob Ivarssonbf087452021-11-11 12:43:492552 voice_media_info.senders[0].target_bitrate = 32000;
Oskar Sundbomcbc71b22017-11-16 09:56:072553 voice_media_info.senders[0].codec_payload_type = 42;
Philipp Hancke684e2412022-07-28 10:41:002554 voice_media_info.senders[0].active = true;
hbos0adb8282016-11-23 10:32:062555
2556 RtpCodecParameters codec_parameters;
2557 codec_parameters.payload_type = 42;
deadbeefe702b302017-02-04 20:09:012558 codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
2559 codec_parameters.name = "dummy";
Oskar Sundbomcbc71b22017-11-16 09:56:072560 codec_parameters.clock_rate = 0;
hbos0adb8282016-11-23 10:32:062561 voice_media_info.send_codecs.insert(
2562 std::make_pair(codec_parameters.payload_type, codec_parameters));
2563
Tommi19015512022-02-02 10:49:352564 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Steve Anton5b387312018-02-03 00:00:202565 stats_->SetupLocalTrackAndSender(cricket::MEDIA_TYPE_AUDIO,
Henrik Boström646fda02019-05-22 13:49:422566 "LocalAudioTrackID", 1, true,
2567 /*attachment_id=*/50);
hbos6ded1902016-11-01 08:50:462568
Steve Anton5b387312018-02-03 00:00:202569 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos6ded1902016-11-01 08:50:462570
Philipp Hancke1f98b462023-03-07 08:53:592571 RTCOutboundRtpStreamStats expected_audio("OTTransportName1A1",
Philipp Hanckeb81823a2023-01-04 14:17:422572 report->timestamp());
Henrik Boström8dfc90f2022-09-02 07:39:292573 expected_audio.media_source_id = "SA50";
Artem Titovcfea2182021-08-09 23:22:312574 // `expected_audio.remote_id` should be undefined.
Henrik Boström1ab61882022-06-16 15:07:332575 expected_audio.mid = "AudioMid";
hbos3443bb72017-02-07 14:28:112576 expected_audio.ssrc = 1;
Philipp Hancke3bc01662018-08-28 12:55:032577 expected_audio.kind = "audio";
Henrik Boström8dfc90f2022-09-02 07:39:292578 expected_audio.transport_id = "TTransportName1";
2579 expected_audio.codec_id = "COTTransportName1_42";
hbos6ded1902016-11-01 08:50:462580 expected_audio.packets_sent = 2;
Henrik Boströmaebba7b2022-10-26 14:53:032581 expected_audio.total_packet_send_delay = 1;
Henrik Boströmcf96e0f2019-04-17 11:51:532582 expected_audio.retransmitted_packets_sent = 20;
hbos6ded1902016-11-01 08:50:462583 expected_audio.bytes_sent = 3;
Niels Möllerac0a4cb2019-10-09 13:01:332584 expected_audio.header_bytes_sent = 12;
Henrik Boströmcf96e0f2019-04-17 11:51:532585 expected_audio.retransmitted_bytes_sent = 30;
Jakob Ivarssone91c9922021-07-06 07:55:432586 expected_audio.nack_count = 31;
Jakob Ivarssonbf087452021-11-11 12:43:492587 expected_audio.target_bitrate = 32000;
Philipp Hancke684e2412022-07-28 10:41:002588 expected_audio.active = true;
hboscd195be2017-02-07 16:31:272589
hboscd195be2017-02-07 16:31:272590 ASSERT_TRUE(report->Get(expected_audio.id()));
hbosa51d4f32017-02-16 13:34:482591 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);
skvladed02c6d2017-02-07 18:45:312594
hbosa51d4f32017-02-16 13:34:482595 ASSERT_TRUE(report->Get(expected_audio.id()));
2596 EXPECT_EQ(
Philipp Hancke1f98b462023-03-07 08:53:592597 report->Get(expected_audio.id())->cast_to<RTCOutboundRtpStreamStats>(),
hbosa51d4f32017-02-16 13:34:482598 expected_audio);
hbos84abeb12017-01-16 14:16:442599 EXPECT_TRUE(report->Get(*expected_audio.transport_id));
2600 EXPECT_TRUE(report->Get(*expected_audio.codec_id));
hbos6ded1902016-11-01 08:50:462601}
2602
Philipp Hancke1f98b462023-03-07 08:53:592603TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRtpStreamStats_Video) {
hbos6ded1902016-11-01 08:50:462604 cricket::VideoMediaInfo video_media_info;
hbos0adb8282016-11-23 10:32:062605
hbos6ded1902016-11-01 08:50:462606 video_media_info.senders.push_back(cricket::VideoSenderInfo());
2607 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
2608 video_media_info.senders[0].local_stats[0].ssrc = 1;
Philipp Hancke6a7bf102023-04-21 17:32:422609 video_media_info.senders[0].firs_received = 2;
2610 video_media_info.senders[0].plis_received = 3;
2611 video_media_info.senders[0].nacks_received = 4;
hbos6ded1902016-11-01 08:50:462612 video_media_info.senders[0].packets_sent = 5;
Henrik Boströmcf96e0f2019-04-17 11:51:532613 video_media_info.senders[0].retransmitted_packets_sent = 50;
Niels Möllerac0a4cb2019-10-09 13:01:332614 video_media_info.senders[0].payload_bytes_sent = 6;
2615 video_media_info.senders[0].header_and_padding_bytes_sent = 12;
Henrik Boströmcf96e0f2019-04-17 11:51:532616 video_media_info.senders[0].retransmitted_bytes_sent = 60;
Oskar Sundbomcbc71b22017-11-16 09:56:072617 video_media_info.senders[0].codec_payload_type = 42;
hbos6769c492017-01-02 16:35:132618 video_media_info.senders[0].frames_encoded = 8;
Rasmus Brandt2efae772019-06-27 12:29:342619 video_media_info.senders[0].key_frames_encoded = 3;
Henrik Boströmf71362f2019-04-08 14:14:232620 video_media_info.senders[0].total_encode_time_ms = 9000;
Henrik Boström23aff9b2019-05-20 13:15:382621 video_media_info.senders[0].total_encoded_bytes_target = 1234;
Harald Alvestranda6544372023-11-13 09:33:562622 video_media_info.senders[0].total_packet_send_delay = TimeDelta::Seconds(10);
Henrik Boströmce33b6a2019-05-28 15:42:382623 video_media_info.senders[0].quality_limitation_reason =
2624 QualityLimitationReason::kBandwidth;
Harald Alvestranda6544372023-11-13 09:33:562625 video_media_info.senders[0]
2626 .quality_limitation_durations_ms[QualityLimitationReason::kBandwidth] =
2627 300;
Evan Shrubsolecc62b162019-09-09 09:26:452628 video_media_info.senders[0].quality_limitation_resolution_changes = 56u;
Danil Chapovalov66cadcc2018-06-19 14:47:432629 video_media_info.senders[0].qp_sum = absl::nullopt;
Henrik Boström2e069262019-04-09 11:59:312630 video_media_info.senders[0].content_type = VideoContentType::UNSPECIFIED;
Philipp Hancke656817c2023-06-22 09:41:352631 video_media_info.senders[0].encoder_implementation_name = absl::nullopt;
Evan Shrubsole13c0be42022-10-31 11:03:102632 video_media_info.senders[0].power_efficient_encoder = false;
Henrik Boströma0ff50c2020-05-05 13:54:462633 video_media_info.senders[0].send_frame_width = 200;
2634 video_media_info.senders[0].send_frame_height = 100;
2635 video_media_info.senders[0].framerate_sent = 10;
2636 video_media_info.senders[0].frames_sent = 5;
2637 video_media_info.senders[0].huge_frames_sent = 2;
Philipp Hancke684e2412022-07-28 10:41:002638 video_media_info.senders[0].active = false;
Evan Shrubsole9b235cd2022-12-06 10:09:102639 video_media_info.senders[0].scalability_mode = ScalabilityMode::kL3T3_KEY;
Philipp Hancke9b82b2f2023-07-28 10:27:132640 video_media_info.senders[0].ssrc_groups.push_back(
2641 {cricket::kFidSsrcGroupSemantics, {1, 4404}});
Henrik Boströma0ff50c2020-05-05 13:54:462642 video_media_info.aggregated_senders.push_back(video_media_info.senders[0]);
hbos0adb8282016-11-23 10:32:062643 RtpCodecParameters codec_parameters;
2644 codec_parameters.payload_type = 42;
deadbeefe702b302017-02-04 20:09:012645 codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
2646 codec_parameters.name = "dummy";
Oskar Sundbomcbc71b22017-11-16 09:56:072647 codec_parameters.clock_rate = 0;
hbos0adb8282016-11-23 10:32:062648 video_media_info.send_codecs.insert(
2649 std::make_pair(codec_parameters.payload_type, codec_parameters));
2650
Harald Alvestrand2f553702023-03-07 10:10:032651 auto video_media_channels =
Tommi19015512022-02-02 10:49:352652 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Steve Anton5b387312018-02-03 00:00:202653 stats_->SetupLocalTrackAndSender(cricket::MEDIA_TYPE_VIDEO,
Henrik Boström646fda02019-05-22 13:49:422654 "LocalVideoTrackID", 1, true,
2655 /*attachment_id=*/50);
hbos6ded1902016-11-01 08:50:462656
Steve Anton5b387312018-02-03 00:00:202657 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos6ded1902016-11-01 08:50:462658
Philipp Hancke1f98b462023-03-07 08:53:592659 auto stats_of_my_type = report->GetStatsOfType<RTCOutboundRtpStreamStats>();
Mirko Bonadeie12c1fe2018-07-03 10:53:232660 ASSERT_EQ(1U, stats_of_my_type.size());
Harald Alvestranda3dab842018-01-14 08:18:582661
Philipp Hancke1f98b462023-03-07 08:53:592662 RTCOutboundRtpStreamStats expected_video(stats_of_my_type[0]->id(),
Philipp Hanckeb81823a2023-01-04 14:17:422663 report->timestamp());
Henrik Boström8dfc90f2022-09-02 07:39:292664 expected_video.media_source_id = "SV50";
Artem Titovcfea2182021-08-09 23:22:312665 // `expected_video.remote_id` should be undefined.
Henrik Boström1ab61882022-06-16 15:07:332666 expected_video.mid = "VideoMid";
hbos3443bb72017-02-07 14:28:112667 expected_video.ssrc = 1;
Philipp Hancke3bc01662018-08-28 12:55:032668 expected_video.kind = "video";
Henrik Boström8dfc90f2022-09-02 07:39:292669 expected_video.transport_id = "TTransportName1";
2670 expected_video.codec_id = "COTTransportName1_42";
hbos6ded1902016-11-01 08:50:462671 expected_video.fir_count = 2;
2672 expected_video.pli_count = 3;
2673 expected_video.nack_count = 4;
2674 expected_video.packets_sent = 5;
Henrik Boströmcf96e0f2019-04-17 11:51:532675 expected_video.retransmitted_packets_sent = 50;
hbos6ded1902016-11-01 08:50:462676 expected_video.bytes_sent = 6;
Niels Möllerac0a4cb2019-10-09 13:01:332677 expected_video.header_bytes_sent = 12;
Henrik Boströmcf96e0f2019-04-17 11:51:532678 expected_video.retransmitted_bytes_sent = 60;
skvladed02c6d2017-02-07 18:45:312679 expected_video.frames_encoded = 8;
Rasmus Brandt2efae772019-06-27 12:29:342680 expected_video.key_frames_encoded = 3;
Henrik Boströmf71362f2019-04-08 14:14:232681 expected_video.total_encode_time = 9.0;
Henrik Boström23aff9b2019-05-20 13:15:382682 expected_video.total_encoded_bytes_target = 1234;
Henrik Boström9fe18342019-05-16 16:38:202683 expected_video.total_packet_send_delay = 10.0;
Henrik Boströmce33b6a2019-05-28 15:42:382684 expected_video.quality_limitation_reason = "bandwidth";
Byoungchan Lee7d235352021-05-28 12:32:042685 expected_video.quality_limitation_durations = std::map<std::string, double>{
Philipp Hancke3fd9cbc2022-01-10 16:41:432686 std::pair<std::string, double>{"bandwidth", 0.3},
Byoungchan Lee7d235352021-05-28 12:32:042687 };
Evan Shrubsolecc62b162019-09-09 09:26:452688 expected_video.quality_limitation_resolution_changes = 56u;
Eldar Rello9276e2c2020-06-10 14:53:392689 expected_video.frame_width = 200u;
2690 expected_video.frame_height = 100u;
2691 expected_video.frames_per_second = 10.0;
2692 expected_video.frames_sent = 5;
2693 expected_video.huge_frames_sent = 2;
Philipp Hancke684e2412022-07-28 10:41:002694 expected_video.active = false;
Evan Shrubsole13c0be42022-10-31 11:03:102695 expected_video.power_efficient_encoder = false;
Evan Shrubsole9b235cd2022-12-06 10:09:102696 expected_video.scalability_mode = "L3T3_KEY";
Philipp Hancke9b82b2f2023-07-28 10:27:132697 expected_video.rtx_ssrc = 4404;
Artem Titovcfea2182021-08-09 23:22:312698 // `expected_video.content_type` should be undefined.
2699 // `expected_video.qp_sum` should be undefined.
2700 // `expected_video.encoder_implementation` should be undefined.
hboscd195be2017-02-07 16:31:272701 ASSERT_TRUE(report->Get(expected_video.id()));
Harald Alvestranda3dab842018-01-14 08:18:582702
hbosa51d4f32017-02-16 13:34:482703 EXPECT_EQ(
Philipp Hancke1f98b462023-03-07 08:53:592704 report->Get(expected_video.id())->cast_to<RTCOutboundRtpStreamStats>(),
hbosa51d4f32017-02-16 13:34:482705 expected_video);
skvladed02c6d2017-02-07 18:45:312706
hbosa51d4f32017-02-16 13:34:482707 // Set previously undefined values and "GetStats" again.
Oskar Sundbomcbc71b22017-11-16 09:56:072708 video_media_info.senders[0].qp_sum = 9;
hbosa51d4f32017-02-16 13:34:482709 expected_video.qp_sum = 9;
Henrik Boström2e069262019-04-09 11:59:312710 video_media_info.senders[0].content_type = VideoContentType::SCREENSHARE;
2711 expected_video.content_type = "screenshare";
Henrik Boström6b430862019-08-16 11:09:512712 video_media_info.senders[0].encoder_implementation_name = "libfooencoder";
Henrik Boströma0ff50c2020-05-05 13:54:462713 video_media_info.aggregated_senders[0] = video_media_info.senders[0];
Henrik Boström6b430862019-08-16 11:09:512714 expected_video.encoder_implementation = "libfooencoder";
Evan Shrubsole13c0be42022-10-31 11:03:102715 video_media_info.senders[0].power_efficient_encoder = true;
2716 expected_video.power_efficient_encoder = true;
Harald Alvestrand2f553702023-03-07 10:10:032717 video_media_channels.first->SetStats(video_media_info);
2718 video_media_channels.second->SetStats(video_media_info);
hbosa51d4f32017-02-16 13:34:482719
Steve Anton5b387312018-02-03 00:00:202720 report = stats_->GetFreshStatsReport();
hbosa51d4f32017-02-16 13:34:482721
2722 ASSERT_TRUE(report->Get(expected_video.id()));
2723 EXPECT_EQ(
Philipp Hancke1f98b462023-03-07 08:53:592724 report->Get(expected_video.id())->cast_to<RTCOutboundRtpStreamStats>(),
hbosa51d4f32017-02-16 13:34:482725 expected_video);
hbos84abeb12017-01-16 14:16:442726 EXPECT_TRUE(report->Get(*expected_video.transport_id));
2727 EXPECT_TRUE(report->Get(*expected_video.codec_id));
hbos6ded1902016-11-01 08:50:462728}
2729
hbos2fa7c672016-10-24 11:00:052730TEST_F(RTCStatsCollectorTest, CollectRTCTransportStats) {
Steve Anton5b387312018-02-03 00:00:202731 const char kTransportName[] = "transport";
2732
2733 pc_->AddVoiceChannel("audio", kTransportName);
2734
Gary Liu37e489c2017-11-21 18:49:362735 std::unique_ptr<cricket::Candidate> rtp_local_candidate =
2736 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
2737 cricket::LOCAL_PORT_TYPE, 42);
hbos2fa7c672016-10-24 11:00:052738 std::unique_ptr<cricket::Candidate> rtp_remote_candidate =
2739 CreateFakeCandidate("42.42.42.42", 42, "protocol",
Gary Liu37e489c2017-11-21 18:49:362740 rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
2741 42);
hbos2fa7c672016-10-24 11:00:052742 std::unique_ptr<cricket::Candidate> rtcp_local_candidate =
Gary Liu37e489c2017-11-21 18:49:362743 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
hbos2fa7c672016-10-24 11:00:052744 cricket::LOCAL_PORT_TYPE, 42);
2745 std::unique_ptr<cricket::Candidate> rtcp_remote_candidate =
2746 CreateFakeCandidate("42.42.42.42", 42, "protocol",
Gary Liu37e489c2017-11-21 18:49:362747 rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
2748 42);
hbos2fa7c672016-10-24 11:00:052749
hbos2fa7c672016-10-24 11:00:052750 cricket::ConnectionInfo rtp_connection_info;
2751 rtp_connection_info.best_connection = false;
2752 rtp_connection_info.local_candidate = *rtp_local_candidate.get();
2753 rtp_connection_info.remote_candidate = *rtp_remote_candidate.get();
2754 rtp_connection_info.sent_total_bytes = 42;
2755 rtp_connection_info.recv_total_bytes = 1337;
Artem Titovedacbd52020-07-06 14:06:372756 rtp_connection_info.sent_total_packets = 3;
2757 rtp_connection_info.sent_discarded_packets = 2;
2758 rtp_connection_info.packets_received = 4;
hbos2fa7c672016-10-24 11:00:052759 cricket::TransportChannelStats rtp_transport_channel_stats;
2760 rtp_transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
Jonas Oreland149dc722019-08-28 06:10:272761 rtp_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
2762 rtp_connection_info);
Mirko Bonadei9f6808b2021-05-21 18:46:092763 rtp_transport_channel_stats.dtls_state = DtlsTransportState::kNew;
Jonas Oreland42da5a92022-03-01 12:55:372764 rtp_transport_channel_stats.ice_transport_stats.bytes_sent = 42;
2765 rtp_transport_channel_stats.ice_transport_stats.packets_sent = 1;
2766 rtp_transport_channel_stats.ice_transport_stats.bytes_received = 1337;
2767 rtp_transport_channel_stats.ice_transport_stats.packets_received = 4;
Jonas Oreland149dc722019-08-28 06:10:272768 rtp_transport_channel_stats.ice_transport_stats
2769 .selected_candidate_pair_changes = 1;
Philipp Hancke95b1a342022-05-05 05:53:542770 rtp_transport_channel_stats.ice_transport_stats.ice_local_username_fragment =
2771 "thelocalufrag";
Steve Anton5b387312018-02-03 00:00:202772 pc_->SetTransportStats(kTransportName, {rtp_transport_channel_stats});
hbos2fa7c672016-10-24 11:00:052773
2774 // Get stats without RTCP, an active connection or certificates.
Steve Anton5b387312018-02-03 00:00:202775 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos0583b282016-11-30 09:50:142776
2777 RTCTransportStats expected_rtp_transport(
Henrik Boström8dfc90f2022-09-02 07:39:292778 "Ttransport" + rtc::ToString(cricket::ICE_CANDIDATE_COMPONENT_RTP),
Philipp Hanckeb81823a2023-01-04 14:17:422779 report->timestamp());
hbos0583b282016-11-30 09:50:142780 expected_rtp_transport.bytes_sent = 42;
Artem Titovedacbd52020-07-06 14:06:372781 expected_rtp_transport.packets_sent = 1;
hbos0583b282016-11-30 09:50:142782 expected_rtp_transport.bytes_received = 1337;
Artem Titovedacbd52020-07-06 14:06:372783 expected_rtp_transport.packets_received = 4;
Henrik Boströmc929ab42023-06-15 13:17:452784 expected_rtp_transport.dtls_state = "new";
2785 expected_rtp_transport.dtls_role = "unknown";
Jonas Oreland149dc722019-08-28 06:10:272786 expected_rtp_transport.selected_candidate_pair_changes = 1;
Henrik Boströmc929ab42023-06-15 13:17:452787 expected_rtp_transport.ice_role = "unknown";
Philipp Hancke95b1a342022-05-05 05:53:542788 expected_rtp_transport.ice_local_username_fragment = "thelocalufrag";
Henrik Boströmc929ab42023-06-15 13:17:452789 expected_rtp_transport.ice_state = "new";
hbos0583b282016-11-30 09:50:142790
hbosdbb64d82016-12-21 09:57:462791 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
hbos0583b282016-11-30 09:50:142792 EXPECT_EQ(
2793 expected_rtp_transport,
2794 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
hbos2fa7c672016-10-24 11:00:052795
2796 cricket::ConnectionInfo rtcp_connection_info;
2797 rtcp_connection_info.best_connection = false;
2798 rtcp_connection_info.local_candidate = *rtcp_local_candidate.get();
2799 rtcp_connection_info.remote_candidate = *rtcp_remote_candidate.get();
2800 rtcp_connection_info.sent_total_bytes = 1337;
2801 rtcp_connection_info.recv_total_bytes = 42;
Artem Titovedacbd52020-07-06 14:06:372802 rtcp_connection_info.sent_total_packets = 3;
2803 rtcp_connection_info.sent_discarded_packets = 2;
2804 rtcp_connection_info.packets_received = 4;
hbos2fa7c672016-10-24 11:00:052805 cricket::TransportChannelStats rtcp_transport_channel_stats;
2806 rtcp_transport_channel_stats.component =
2807 cricket::ICE_CANDIDATE_COMPONENT_RTCP;
Jonas Oreland149dc722019-08-28 06:10:272808 rtcp_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
2809 rtcp_connection_info);
Mirko Bonadei9f6808b2021-05-21 18:46:092810 rtcp_transport_channel_stats.dtls_state = DtlsTransportState::kConnecting;
Jonas Oreland42da5a92022-03-01 12:55:372811 rtcp_transport_channel_stats.ice_transport_stats.bytes_sent = 1337;
2812 rtcp_transport_channel_stats.ice_transport_stats.packets_sent = 1;
2813 rtcp_transport_channel_stats.ice_transport_stats.bytes_received = 42;
2814 rtcp_transport_channel_stats.ice_transport_stats.packets_received = 4;
Philipp Hancke95b1a342022-05-05 05:53:542815 rtcp_transport_channel_stats.ice_transport_stats.ice_local_username_fragment =
2816 "thelocalufrag";
Philipp Hancke1f491572022-05-09 15:43:312817 rtcp_transport_channel_stats.ice_transport_stats.ice_state =
2818 IceTransportState::kChecking;
Steve Anton5b387312018-02-03 00:00:202819 pc_->SetTransportStats(kTransportName, {rtp_transport_channel_stats,
2820 rtcp_transport_channel_stats});
hbos2fa7c672016-10-24 11:00:052821
hbos2fa7c672016-10-24 11:00:052822 // Get stats with RTCP and without an active connection or certificates.
Steve Anton5b387312018-02-03 00:00:202823 report = stats_->GetFreshStatsReport();
hbos0583b282016-11-30 09:50:142824
2825 RTCTransportStats expected_rtcp_transport(
Henrik Boström8dfc90f2022-09-02 07:39:292826 "Ttransport" + rtc::ToString(cricket::ICE_CANDIDATE_COMPONENT_RTCP),
Philipp Hanckeb81823a2023-01-04 14:17:422827 report->timestamp());
hbos0583b282016-11-30 09:50:142828 expected_rtcp_transport.bytes_sent = 1337;
Artem Titovedacbd52020-07-06 14:06:372829 expected_rtcp_transport.packets_sent = 1;
hbos0583b282016-11-30 09:50:142830 expected_rtcp_transport.bytes_received = 42;
Artem Titovedacbd52020-07-06 14:06:372831 expected_rtcp_transport.packets_received = 4;
Henrik Boströmc929ab42023-06-15 13:17:452832 expected_rtcp_transport.dtls_state = "connecting";
2833 expected_rtcp_transport.dtls_role = "unknown";
Jonas Oreland149dc722019-08-28 06:10:272834 expected_rtcp_transport.selected_candidate_pair_changes = 0;
Henrik Boströmc929ab42023-06-15 13:17:452835 expected_rtcp_transport.ice_role = "unknown";
Philipp Hancke95b1a342022-05-05 05:53:542836 expected_rtcp_transport.ice_local_username_fragment = "thelocalufrag";
Henrik Boströmc929ab42023-06-15 13:17:452837 expected_rtcp_transport.ice_state = "checking";
hbos0583b282016-11-30 09:50:142838
2839 expected_rtp_transport.rtcp_transport_stats_id = expected_rtcp_transport.id();
hbosdbb64d82016-12-21 09:57:462840 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
hbos0583b282016-11-30 09:50:142841 EXPECT_EQ(
2842 expected_rtp_transport,
2843 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
hbosdbb64d82016-12-21 09:57:462844 ASSERT_TRUE(report->Get(expected_rtcp_transport.id()));
hbos0583b282016-11-30 09:50:142845 EXPECT_EQ(
2846 expected_rtcp_transport,
2847 report->Get(expected_rtcp_transport.id())->cast_to<RTCTransportStats>());
hbos2fa7c672016-10-24 11:00:052848
hbos7064d592017-01-16 15:38:022849 // Get stats with an active connection (selected candidate pair).
Jonas Oreland149dc722019-08-28 06:10:272850 rtcp_transport_channel_stats.ice_transport_stats.connection_infos[0]
2851 .best_connection = true;
Steve Anton5b387312018-02-03 00:00:202852 pc_->SetTransportStats(kTransportName, {rtp_transport_channel_stats,
2853 rtcp_transport_channel_stats});
hbos2fa7c672016-10-24 11:00:052854
Steve Anton5b387312018-02-03 00:00:202855 report = stats_->GetFreshStatsReport();
hbos0583b282016-11-30 09:50:142856
hbos0583b282016-11-30 09:50:142857 expected_rtcp_transport.selected_candidate_pair_id =
Henrik Boström8dfc90f2022-09-02 07:39:292858 "CP" + rtcp_local_candidate->id() + "_" + rtcp_remote_candidate->id();
hbos0583b282016-11-30 09:50:142859
hbosdbb64d82016-12-21 09:57:462860 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
hbos0583b282016-11-30 09:50:142861 EXPECT_EQ(
2862 expected_rtp_transport,
2863 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
hbosdbb64d82016-12-21 09:57:462864 ASSERT_TRUE(report->Get(expected_rtcp_transport.id()));
hbos0583b282016-11-30 09:50:142865 EXPECT_EQ(
2866 expected_rtcp_transport,
2867 report->Get(expected_rtcp_transport.id())->cast_to<RTCTransportStats>());
hbos2fa7c672016-10-24 11:00:052868
2869 // Get stats with certificates.
2870 std::unique_ptr<CertificateInfo> local_certinfo =
Steve Anton5b387312018-02-03 00:00:202871 CreateFakeCertificateAndInfoFromDers({"(local) local", "(local) chain"});
2872 pc_->SetLocalCertificate(kTransportName, local_certinfo->certificate);
hbos2fa7c672016-10-24 11:00:052873 std::unique_ptr<CertificateInfo> remote_certinfo =
2874 CreateFakeCertificateAndInfoFromDers(
Steve Anton5b387312018-02-03 00:00:202875 {"(remote) local", "(remote) chain"});
Taylor Brandstetterc3928662018-02-23 21:04:512876 pc_->SetRemoteCertChain(
Benjamin Wright6c6c9df2018-10-25 08:16:262877 kTransportName,
2878 remote_certinfo->certificate->GetSSLCertificateChain().Clone());
hbos2fa7c672016-10-24 11:00:052879
Steve Anton5b387312018-02-03 00:00:202880 report = stats_->GetFreshStatsReport();
hbos0583b282016-11-30 09:50:142881
2882 expected_rtp_transport.local_certificate_id =
Henrik Boström8dfc90f2022-09-02 07:39:292883 "CF" + local_certinfo->fingerprints[0];
hbos0583b282016-11-30 09:50:142884 expected_rtp_transport.remote_certificate_id =
Henrik Boström8dfc90f2022-09-02 07:39:292885 "CF" + remote_certinfo->fingerprints[0];
hbos0583b282016-11-30 09:50:142886
2887 expected_rtcp_transport.local_certificate_id =
2888 *expected_rtp_transport.local_certificate_id;
2889 expected_rtcp_transport.remote_certificate_id =
2890 *expected_rtp_transport.remote_certificate_id;
2891
hbosdbb64d82016-12-21 09:57:462892 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
hbos0583b282016-11-30 09:50:142893 EXPECT_EQ(
2894 expected_rtp_transport,
2895 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
hbosdbb64d82016-12-21 09:57:462896 ASSERT_TRUE(report->Get(expected_rtcp_transport.id()));
hbos0583b282016-11-30 09:50:142897 EXPECT_EQ(
2898 expected_rtcp_transport,
2899 report->Get(expected_rtcp_transport.id())->cast_to<RTCTransportStats>());
hbos2fa7c672016-10-24 11:00:052900}
2901
Harald Alvestrand5cb78072019-10-28 08:51:172902TEST_F(RTCStatsCollectorTest, CollectRTCTransportStatsWithCrypto) {
2903 const char kTransportName[] = "transport";
2904
2905 pc_->AddVoiceChannel("audio", kTransportName);
2906
2907 std::unique_ptr<cricket::Candidate> rtp_local_candidate =
2908 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
2909 cricket::LOCAL_PORT_TYPE, 42);
2910 std::unique_ptr<cricket::Candidate> rtp_remote_candidate =
2911 CreateFakeCandidate("42.42.42.42", 42, "protocol",
2912 rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
2913 42);
2914 std::unique_ptr<cricket::Candidate> rtcp_local_candidate =
2915 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
2916 cricket::LOCAL_PORT_TYPE, 42);
2917 std::unique_ptr<cricket::Candidate> rtcp_remote_candidate =
2918 CreateFakeCandidate("42.42.42.42", 42, "protocol",
2919 rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
2920 42);
2921
2922 cricket::ConnectionInfo rtp_connection_info;
2923 rtp_connection_info.best_connection = false;
2924 rtp_connection_info.local_candidate = *rtp_local_candidate.get();
2925 rtp_connection_info.remote_candidate = *rtp_remote_candidate.get();
Harald Alvestrand5cb78072019-10-28 08:51:172926 cricket::TransportChannelStats rtp_transport_channel_stats;
2927 rtp_transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
2928 rtp_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
2929 rtp_connection_info);
2930 // The state must be connected in order for crypto parameters to show up.
Mirko Bonadei9f6808b2021-05-21 18:46:092931 rtp_transport_channel_stats.dtls_state = DtlsTransportState::kConnected;
Harald Alvestrand5cb78072019-10-28 08:51:172932 rtp_transport_channel_stats.ice_transport_stats
2933 .selected_candidate_pair_changes = 1;
2934 rtp_transport_channel_stats.ssl_version_bytes = 0x0203;
Philipp Hancke69c1df22022-04-22 13:46:242935 rtp_transport_channel_stats.dtls_role = rtc::SSL_CLIENT;
Philipp Hanckecc1b9b02022-05-04 16:58:262936 rtp_transport_channel_stats.ice_transport_stats.ice_role =
2937 cricket::ICEROLE_CONTROLLING;
Philipp Hancke95b1a342022-05-05 05:53:542938 rtp_transport_channel_stats.ice_transport_stats.ice_local_username_fragment =
2939 "thelocalufrag";
Philipp Hancke1f491572022-05-09 15:43:312940 rtp_transport_channel_stats.ice_transport_stats.ice_state =
2941 IceTransportState::kConnected;
Harald Alvestrand5cb78072019-10-28 08:51:172942 // 0x2F is TLS_RSA_WITH_AES_128_CBC_SHA according to IANA
2943 rtp_transport_channel_stats.ssl_cipher_suite = 0x2F;
Mirko Bonadei7750d802021-07-26 15:27:422944 rtp_transport_channel_stats.srtp_crypto_suite = rtc::kSrtpAes128CmSha1_80;
Harald Alvestrand5cb78072019-10-28 08:51:172945 pc_->SetTransportStats(kTransportName, {rtp_transport_channel_stats});
2946
2947 // Get stats
2948 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
2949
2950 RTCTransportStats expected_rtp_transport(
Henrik Boström8dfc90f2022-09-02 07:39:292951 "Ttransport" + rtc::ToString(cricket::ICE_CANDIDATE_COMPONENT_RTP),
Philipp Hanckeb81823a2023-01-04 14:17:422952 report->timestamp());
Henrik Boströmc929ab42023-06-15 13:17:452953 expected_rtp_transport.dtls_state = "connected";
Harald Alvestrand5cb78072019-10-28 08:51:172954 expected_rtp_transport.selected_candidate_pair_changes = 1;
Henrik Boströmc929ab42023-06-15 13:17:452955 expected_rtp_transport.ice_role = "unknown";
Jonas Oreland42da5a92022-03-01 12:55:372956 expected_rtp_transport.bytes_sent = 0;
2957 expected_rtp_transport.bytes_received = 0;
2958 expected_rtp_transport.packets_sent = 0;
2959 expected_rtp_transport.packets_received = 0;
Henrik Boströmc929ab42023-06-15 13:17:452960 expected_rtp_transport.ice_role = "controlling";
Philipp Hancke95b1a342022-05-05 05:53:542961 expected_rtp_transport.ice_local_username_fragment = "thelocalufrag";
Philipp Hancke1f491572022-05-09 15:43:312962 expected_rtp_transport.ice_state = "connected";
Harald Alvestrand5cb78072019-10-28 08:51:172963 // Crypto parameters
2964 expected_rtp_transport.tls_version = "0203";
Henrik Boströmc929ab42023-06-15 13:17:452965 expected_rtp_transport.dtls_role = "client";
Harald Alvestrand5cb78072019-10-28 08:51:172966 expected_rtp_transport.dtls_cipher = "TLS_RSA_WITH_AES_128_CBC_SHA";
2967 expected_rtp_transport.srtp_cipher = "AES_CM_128_HMAC_SHA1_80";
2968
2969 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
2970 EXPECT_EQ(
2971 expected_rtp_transport,
2972 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
2973}
2974
Philipp Hancke1f98b462023-03-07 08:53:592975TEST_F(RTCStatsCollectorTest, CollectNoStreamRTCOutboundRtpStreamStats_Audio) {
Harald Alvestrand89061872018-01-02 13:08:342976 cricket::VoiceMediaInfo voice_media_info;
2977
2978 voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
2979 voice_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
2980 voice_media_info.senders[0].local_stats[0].ssrc = 1;
2981 voice_media_info.senders[0].packets_sent = 2;
Henrik Boströmaebba7b2022-10-26 14:53:032982 voice_media_info.senders[0].total_packet_send_delay = TimeDelta::Seconds(0.5);
Henrik Boströmcf96e0f2019-04-17 11:51:532983 voice_media_info.senders[0].retransmitted_packets_sent = 20;
Niels Möllerac0a4cb2019-10-09 13:01:332984 voice_media_info.senders[0].payload_bytes_sent = 3;
2985 voice_media_info.senders[0].header_and_padding_bytes_sent = 4;
Henrik Boströmcf96e0f2019-04-17 11:51:532986 voice_media_info.senders[0].retransmitted_bytes_sent = 30;
Philipp Hancke6a7bf102023-04-21 17:32:422987 voice_media_info.senders[0].nacks_received = 31;
Harald Alvestrand89061872018-01-02 13:08:342988 voice_media_info.senders[0].codec_payload_type = 42;
Philipp Hancke684e2412022-07-28 10:41:002989 voice_media_info.senders[0].active = true;
Harald Alvestrand89061872018-01-02 13:08:342990
2991 RtpCodecParameters codec_parameters;
2992 codec_parameters.payload_type = 42;
2993 codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
2994 codec_parameters.name = "dummy";
2995 codec_parameters.clock_rate = 0;
2996 voice_media_info.send_codecs.insert(
2997 std::make_pair(codec_parameters.payload_type, codec_parameters));
2998
Steve Anton5b387312018-02-03 00:00:202999 // Emulates the case where AddTrack is used without an associated MediaStream
Tommi19015512022-02-02 10:49:353000 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Steve Anton5b387312018-02-03 00:00:203001 stats_->SetupLocalTrackAndSender(cricket::MEDIA_TYPE_AUDIO,
Henrik Boström646fda02019-05-22 13:49:423002 "LocalAudioTrackID", 1, false,
3003 /*attachment_id=*/50);
Harald Alvestrand89061872018-01-02 13:08:343004
Steve Anton5b387312018-02-03 00:00:203005 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Harald Alvestrand89061872018-01-02 13:08:343006
Philipp Hancke1f98b462023-03-07 08:53:593007 RTCOutboundRtpStreamStats expected_audio("OTTransportName1A1",
Philipp Hanckeb81823a2023-01-04 14:17:423008 report->timestamp());
Henrik Boström8dfc90f2022-09-02 07:39:293009 expected_audio.media_source_id = "SA50";
Henrik Boström1ab61882022-06-16 15:07:333010 expected_audio.mid = "AudioMid";
Harald Alvestrand89061872018-01-02 13:08:343011 expected_audio.ssrc = 1;
Philipp Hancke3bc01662018-08-28 12:55:033012 expected_audio.kind = "audio";
Henrik Boström8dfc90f2022-09-02 07:39:293013 expected_audio.transport_id = "TTransportName1";
3014 expected_audio.codec_id = "COTTransportName1_42";
Harald Alvestrand89061872018-01-02 13:08:343015 expected_audio.packets_sent = 2;
Henrik Boströmaebba7b2022-10-26 14:53:033016 expected_audio.total_packet_send_delay = 0.5;
Henrik Boströmcf96e0f2019-04-17 11:51:533017 expected_audio.retransmitted_packets_sent = 20;
Harald Alvestrand89061872018-01-02 13:08:343018 expected_audio.bytes_sent = 3;
Niels Möllerac0a4cb2019-10-09 13:01:333019 expected_audio.header_bytes_sent = 4;
Henrik Boströmcf96e0f2019-04-17 11:51:533020 expected_audio.retransmitted_bytes_sent = 30;
Jakob Ivarssone91c9922021-07-06 07:55:433021 expected_audio.nack_count = 31;
Philipp Hancke684e2412022-07-28 10:41:003022 expected_audio.active = true;
Harald Alvestrand89061872018-01-02 13:08:343023
3024 ASSERT_TRUE(report->Get(expected_audio.id()));
3025 EXPECT_EQ(
Philipp Hancke1f98b462023-03-07 08:53:593026 report->Get(expected_audio.id())->cast_to<RTCOutboundRtpStreamStats>(),
Harald Alvestrand89061872018-01-02 13:08:343027 expected_audio);
Harald Alvestrand89061872018-01-02 13:08:343028 EXPECT_TRUE(report->Get(*expected_audio.transport_id));
3029 EXPECT_TRUE(report->Get(*expected_audio.codec_id));
3030}
3031
Henrik Boström646fda02019-05-22 13:49:423032TEST_F(RTCStatsCollectorTest, RTCAudioSourceStatsCollectedForSenderWithTrack) {
3033 const uint32_t kSsrc = 4;
3034 const int kAttachmentId = 42;
3035
3036 cricket::VoiceMediaInfo voice_media_info;
3037 voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
3038 voice_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3039 voice_media_info.senders[0].local_stats[0].ssrc = kSsrc;
Henrik Boströmd2c336f2019-07-03 15:11:103040 voice_media_info.senders[0].audio_level = 32767; // [0,32767]
3041 voice_media_info.senders[0].total_input_energy = 2.0;
3042 voice_media_info.senders[0].total_input_duration = 3.0;
Taylor Brandstetter64851c02021-06-24 20:32:503043 voice_media_info.senders[0].apm_statistics.echo_return_loss = 42.0;
3044 voice_media_info.senders[0].apm_statistics.echo_return_loss_enhancement =
3045 52.0;
Tommi19015512022-02-02 10:49:353046 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Henrik Boström646fda02019-05-22 13:49:423047 stats_->SetupLocalTrackAndSender(cricket::MEDIA_TYPE_AUDIO,
3048 "LocalAudioTrackID", kSsrc, false,
3049 kAttachmentId);
3050
3051 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3052
Philipp Hanckeb81823a2023-01-04 14:17:423053 RTCAudioSourceStats expected_audio("SA42", report->timestamp());
Henrik Boström646fda02019-05-22 13:49:423054 expected_audio.track_identifier = "LocalAudioTrackID";
3055 expected_audio.kind = "audio";
Henrik Boströmd2c336f2019-07-03 15:11:103056 expected_audio.audio_level = 1.0; // [0,1]
3057 expected_audio.total_audio_energy = 2.0;
3058 expected_audio.total_samples_duration = 3.0;
Taylor Brandstetter64851c02021-06-24 20:32:503059 expected_audio.echo_return_loss = 42.0;
3060 expected_audio.echo_return_loss_enhancement = 52.0;
Henrik Boström646fda02019-05-22 13:49:423061
3062 ASSERT_TRUE(report->Get(expected_audio.id()));
3063 EXPECT_EQ(report->Get(expected_audio.id())->cast_to<RTCAudioSourceStats>(),
3064 expected_audio);
3065}
3066
3067TEST_F(RTCStatsCollectorTest, RTCVideoSourceStatsCollectedForSenderWithTrack) {
3068 const uint32_t kSsrc = 4;
3069 const int kAttachmentId = 42;
3070 const int kVideoSourceWidth = 12;
3071 const int kVideoSourceHeight = 34;
3072
3073 cricket::VideoMediaInfo video_media_info;
Henrik Boströma0ff50c2020-05-05 13:54:463074 video_media_info.aggregated_senders.push_back(cricket::VideoSenderInfo());
Henrik Boström646fda02019-05-22 13:49:423075 video_media_info.senders.push_back(cricket::VideoSenderInfo());
3076 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3077 video_media_info.senders[0].local_stats[0].ssrc = kSsrc;
Byoungchan Leeefe46b62021-11-10 02:23:563078 video_media_info.senders[0].framerate_input = 29.0;
Henrik Boströma0ff50c2020-05-05 13:54:463079 video_media_info.aggregated_senders[0].local_stats.push_back(
3080 cricket::SsrcSenderInfo());
3081 video_media_info.aggregated_senders[0].local_stats[0].ssrc = kSsrc;
Byoungchan Leeefe46b62021-11-10 02:23:563082 video_media_info.aggregated_senders[0].framerate_input = 29.0;
Di Wu668dbf62021-02-27 08:29:153083 video_media_info.aggregated_senders[0].frames = 10001;
Tommi19015512022-02-02 10:49:353084 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström646fda02019-05-22 13:49:423085
3086 auto video_source = FakeVideoTrackSourceForStats::Create(kVideoSourceWidth,
3087 kVideoSourceHeight);
3088 auto video_track = FakeVideoTrackForStats::Create(
3089 "LocalVideoTrackID", MediaStreamTrackInterface::kLive, video_source);
3090 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
3091 cricket::MEDIA_TYPE_VIDEO, video_track, kSsrc, kAttachmentId, {});
Tommi6589def2022-02-17 22:36:473092 EXPECT_CALL(*sender, Stop());
3093 EXPECT_CALL(*sender, SetMediaChannel(_));
Henrik Boström646fda02019-05-22 13:49:423094 pc_->AddSender(sender);
3095
3096 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3097
Philipp Hanckeb81823a2023-01-04 14:17:423098 RTCVideoSourceStats expected_video("SV42", report->timestamp());
Henrik Boström646fda02019-05-22 13:49:423099 expected_video.track_identifier = "LocalVideoTrackID";
3100 expected_video.kind = "video";
3101 expected_video.width = kVideoSourceWidth;
3102 expected_video.height = kVideoSourceHeight;
Byoungchan Leeefe46b62021-11-10 02:23:563103 expected_video.frames_per_second = 29.0;
Di Wu668dbf62021-02-27 08:29:153104 expected_video.frames = 10001;
Henrik Boström646fda02019-05-22 13:49:423105
3106 ASSERT_TRUE(report->Get(expected_video.id()));
3107 EXPECT_EQ(report->Get(expected_video.id())->cast_to<RTCVideoSourceStats>(),
3108 expected_video);
3109}
3110
3111// This test exercises the current behavior and code path, but the correct
3112// behavior is to report frame rate even if we have no SSRC.
3113// TODO(hbos): When we know the frame rate even if we have no SSRC, update the
3114// expectations of this test.
3115TEST_F(RTCStatsCollectorTest,
3116 RTCVideoSourceStatsMissingFrameRateWhenSenderHasNoSsrc) {
3117 // TODO(https://crbug.com/webrtc/8694): When 0 is no longer a magic value for
3118 // "none", update this test.
3119 const uint32_t kNoSsrc = 0;
3120 const int kAttachmentId = 42;
3121 const int kVideoSourceWidth = 12;
3122 const int kVideoSourceHeight = 34;
3123
3124 cricket::VideoMediaInfo video_media_info;
3125 video_media_info.senders.push_back(cricket::VideoSenderInfo());
3126 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
Byoungchan Leeefe46b62021-11-10 02:23:563127 video_media_info.senders[0].framerate_input = 29.0;
Tommi19015512022-02-02 10:49:353128 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström646fda02019-05-22 13:49:423129
3130 auto video_source = FakeVideoTrackSourceForStats::Create(kVideoSourceWidth,
3131 kVideoSourceHeight);
3132 auto video_track = FakeVideoTrackForStats::Create(
3133 "LocalVideoTrackID", MediaStreamTrackInterface::kLive, video_source);
3134 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
3135 cricket::MEDIA_TYPE_VIDEO, video_track, kNoSsrc, kAttachmentId, {});
Tommi6589def2022-02-17 22:36:473136 EXPECT_CALL(*sender, Stop());
3137 EXPECT_CALL(*sender, SetMediaChannel(_));
Henrik Boström646fda02019-05-22 13:49:423138 pc_->AddSender(sender);
3139
3140 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Henrik Boström8dfc90f2022-09-02 07:39:293141 ASSERT_TRUE(report->Get("SV42"));
3142 auto video_stats = report->Get("SV42")->cast_to<RTCVideoSourceStats>();
Henrik Boströmed1d0842024-01-19 10:27:313143 EXPECT_FALSE(video_stats.frames_per_second.has_value());
3144 EXPECT_FALSE(video_stats.frames.has_value());
Henrik Boström646fda02019-05-22 13:49:423145}
3146
3147// The track not having a source is not expected to be true in practise, but
3148// this is true in some tests relying on fakes. This test covers that code path.
3149TEST_F(RTCStatsCollectorTest,
3150 RTCVideoSourceStatsMissingResolutionWhenTrackHasNoSource) {
3151 const uint32_t kSsrc = 4;
3152 const int kAttachmentId = 42;
3153
3154 cricket::VideoMediaInfo video_media_info;
3155 video_media_info.senders.push_back(cricket::VideoSenderInfo());
3156 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3157 video_media_info.senders[0].local_stats[0].ssrc = kSsrc;
Byoungchan Leeefe46b62021-11-10 02:23:563158 video_media_info.senders[0].framerate_input = 29.0;
Tommi19015512022-02-02 10:49:353159 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström646fda02019-05-22 13:49:423160
3161 auto video_track = FakeVideoTrackForStats::Create(
3162 "LocalVideoTrackID", MediaStreamTrackInterface::kLive,
3163 /*source=*/nullptr);
3164 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
3165 cricket::MEDIA_TYPE_VIDEO, video_track, kSsrc, kAttachmentId, {});
Tommi6589def2022-02-17 22:36:473166 EXPECT_CALL(*sender, Stop());
3167 EXPECT_CALL(*sender, SetMediaChannel(_));
Henrik Boström646fda02019-05-22 13:49:423168 pc_->AddSender(sender);
3169
3170 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Henrik Boström8dfc90f2022-09-02 07:39:293171 ASSERT_TRUE(report->Get("SV42"));
3172 auto video_stats = report->Get("SV42")->cast_to<RTCVideoSourceStats>();
Henrik Boströmed1d0842024-01-19 10:27:313173 EXPECT_FALSE(video_stats.width.has_value());
3174 EXPECT_FALSE(video_stats.height.has_value());
Henrik Boström646fda02019-05-22 13:49:423175}
3176
3177TEST_F(RTCStatsCollectorTest,
3178 RTCAudioSourceStatsNotCollectedForSenderWithoutTrack) {
3179 const uint32_t kSsrc = 4;
3180 const int kAttachmentId = 42;
3181
3182 cricket::VoiceMediaInfo voice_media_info;
3183 voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
3184 voice_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3185 voice_media_info.senders[0].local_stats[0].ssrc = kSsrc;
Tommi19015512022-02-02 10:49:353186 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Henrik Boström646fda02019-05-22 13:49:423187 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
3188 cricket::MEDIA_TYPE_AUDIO, /*track=*/nullptr, kSsrc, kAttachmentId, {});
Tommi6589def2022-02-17 22:36:473189 EXPECT_CALL(*sender, Stop());
3190 EXPECT_CALL(*sender, SetMediaChannel(_));
Henrik Boström646fda02019-05-22 13:49:423191 pc_->AddSender(sender);
3192
3193 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Henrik Boström8dfc90f2022-09-02 07:39:293194 EXPECT_FALSE(report->Get("SA42"));
Henrik Boström646fda02019-05-22 13:49:423195}
3196
Henrik Boström883eefc2019-05-27 11:40:253197// Parameterized tests on cricket::MediaType (audio or video).
3198class RTCStatsCollectorTestWithParamKind
3199 : public RTCStatsCollectorTest,
3200 public ::testing::WithParamInterface<cricket::MediaType> {
3201 public:
3202 RTCStatsCollectorTestWithParamKind() : media_type_(GetParam()) {
3203 RTC_DCHECK(media_type_ == cricket::MEDIA_TYPE_AUDIO ||
3204 media_type_ == cricket::MEDIA_TYPE_VIDEO);
3205 }
3206
Henrik Boström8dfc90f2022-09-02 07:39:293207 std::string MediaTypeCharStr() const {
Henrik Boström883eefc2019-05-27 11:40:253208 switch (media_type_) {
3209 case cricket::MEDIA_TYPE_AUDIO:
Henrik Boström8dfc90f2022-09-02 07:39:293210 return "A";
Henrik Boström883eefc2019-05-27 11:40:253211 case cricket::MEDIA_TYPE_VIDEO:
Henrik Boström8dfc90f2022-09-02 07:39:293212 return "V";
3213 case cricket::MEDIA_TYPE_DATA:
3214 case cricket::MEDIA_TYPE_UNSUPPORTED:
3215 RTC_DCHECK_NOTREACHED();
3216 return "?";
3217 }
3218 }
3219
3220 std::string MediaTypeKind() const {
3221 switch (media_type_) {
3222 case cricket::MEDIA_TYPE_AUDIO:
3223 return "audio";
3224 case cricket::MEDIA_TYPE_VIDEO:
3225 return "video";
Henrik Boström883eefc2019-05-27 11:40:253226 case cricket::MEDIA_TYPE_DATA:
Philipp Hancke4e8c1152020-10-13 10:43:153227 case cricket::MEDIA_TYPE_UNSUPPORTED:
Artem Titovd3251962021-11-15 15:57:073228 RTC_DCHECK_NOTREACHED();
Henrik Boström883eefc2019-05-27 11:40:253229 return "";
3230 }
3231 }
3232
Henrik Boström883eefc2019-05-27 11:40:253233 // Adds a sender and channel of the appropriate kind, creating a sender info
Artem Titov880fa812021-07-30 20:30:233234 // with the report block's `source_ssrc` and report block data.
Eldar Relloc07e9042020-07-03 08:08:073235 void AddSenderInfoAndMediaChannel(
3236 std::string transport_name,
3237 const std::vector<ReportBlockData>& report_block_datas,
3238 absl::optional<RtpCodecParameters> codec) {
Henrik Boström883eefc2019-05-27 11:40:253239 switch (media_type_) {
3240 case cricket::MEDIA_TYPE_AUDIO: {
3241 cricket::VoiceMediaInfo voice_media_info;
Eldar Relloc07e9042020-07-03 08:08:073242 for (const auto& report_block_data : report_block_datas) {
3243 cricket::VoiceSenderInfo sender;
3244 sender.local_stats.push_back(cricket::SsrcSenderInfo());
Danil Chapovalovd5b51672023-05-04 08:56:073245 sender.local_stats[0].ssrc = report_block_data.source_ssrc();
Eldar Relloc07e9042020-07-03 08:08:073246 if (codec.has_value()) {
3247 sender.codec_payload_type = codec->payload_type;
3248 voice_media_info.send_codecs.insert(
3249 std::make_pair(codec->payload_type, *codec));
3250 }
3251 sender.report_block_datas.push_back(report_block_data);
3252 voice_media_info.senders.push_back(sender);
Henrik Boström883eefc2019-05-27 11:40:253253 }
Tommi19015512022-02-02 10:49:353254 pc_->AddVoiceChannel("mid", transport_name, voice_media_info);
Henrik Boström883eefc2019-05-27 11:40:253255 return;
3256 }
3257 case cricket::MEDIA_TYPE_VIDEO: {
3258 cricket::VideoMediaInfo video_media_info;
Eldar Relloc07e9042020-07-03 08:08:073259 for (const auto& report_block_data : report_block_datas) {
3260 cricket::VideoSenderInfo sender;
3261 sender.local_stats.push_back(cricket::SsrcSenderInfo());
Danil Chapovalovd5b51672023-05-04 08:56:073262 sender.local_stats[0].ssrc = report_block_data.source_ssrc();
Eldar Relloc07e9042020-07-03 08:08:073263 if (codec.has_value()) {
3264 sender.codec_payload_type = codec->payload_type;
3265 video_media_info.send_codecs.insert(
3266 std::make_pair(codec->payload_type, *codec));
3267 }
3268 sender.report_block_datas.push_back(report_block_data);
3269 video_media_info.aggregated_senders.push_back(sender);
3270 video_media_info.senders.push_back(sender);
Henrik Boström883eefc2019-05-27 11:40:253271 }
Tommi19015512022-02-02 10:49:353272 pc_->AddVideoChannel("mid", transport_name, video_media_info);
Henrik Boström883eefc2019-05-27 11:40:253273 return;
3274 }
3275 case cricket::MEDIA_TYPE_DATA:
Philipp Hancke4e8c1152020-10-13 10:43:153276 case cricket::MEDIA_TYPE_UNSUPPORTED:
Artem Titovd3251962021-11-15 15:57:073277 RTC_DCHECK_NOTREACHED();
Henrik Boström883eefc2019-05-27 11:40:253278 }
3279 }
3280
3281 protected:
3282 cricket::MediaType media_type_;
3283};
3284
3285// Verifies RTCRemoteInboundRtpStreamStats members that don't require
3286// RTCCodecStats (codecId, jitter) and without setting up an RTCP transport.
3287TEST_P(RTCStatsCollectorTestWithParamKind,
3288 RTCRemoteInboundRtpStreamStatsCollectedFromReportBlock) {
Danil Chapovalovec2670e2023-04-12 11:11:213289 const Timestamp kReportBlockTimestampUtc = Timestamp::Micros(123456789);
Di Wu86f04ad2021-03-01 07:36:033290 const uint8_t kFractionLost = 12;
Danil Chapovalovec2670e2023-04-12 11:11:213291 const TimeDelta kRoundTripTimeSample1 = TimeDelta::Millis(1'234);
3292 const TimeDelta kRoundTripTimeSample2 = TimeDelta::Seconds(13);
Henrik Boström883eefc2019-05-27 11:40:253293
3294 // The report block's timestamp cannot be from the future, set the fake clock
3295 // to match.
Danil Chapovalovec2670e2023-04-12 11:11:213296 fake_clock_.SetTime(kReportBlockTimestampUtc);
Eldar Relloc07e9042020-07-03 08:08:073297 auto ssrcs = {12, 13};
3298 std::vector<ReportBlockData> report_block_datas;
3299 for (auto ssrc : ssrcs) {
Danil Chapovalovec2670e2023-04-12 11:11:213300 rtcp::ReportBlock report_block;
Eldar Relloc07e9042020-07-03 08:08:073301 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
Artem Titov880fa812021-07-30 20:30:233302 // `source_ssrc`, "SSRC of the RTP packet sender".
Danil Chapovalovec2670e2023-04-12 11:11:213303 report_block.SetMediaSsrc(ssrc);
3304 report_block.SetCumulativeLost(7);
3305 report_block.SetFractionLost(kFractionLost);
Eldar Relloc07e9042020-07-03 08:08:073306 ReportBlockData report_block_data;
Danil Chapovalovec2670e2023-04-12 11:11:213307 report_block_data.SetReportBlock(0, report_block, kReportBlockTimestampUtc);
3308 report_block_data.AddRoundTripTimeSample(kRoundTripTimeSample1);
Eldar Relloc07e9042020-07-03 08:08:073309 // Only the last sample should be exposed as the
Artem Titovcfea2182021-08-09 23:22:313310 // `RTCRemoteInboundRtpStreamStats::round_trip_time`.
Danil Chapovalovec2670e2023-04-12 11:11:213311 report_block_data.AddRoundTripTimeSample(kRoundTripTimeSample2);
Eldar Relloc07e9042020-07-03 08:08:073312 report_block_datas.push_back(report_block_data);
3313 }
3314 AddSenderInfoAndMediaChannel("TransportName", report_block_datas,
Henrik Boström883eefc2019-05-27 11:40:253315 absl::nullopt);
3316
3317 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Eldar Relloc07e9042020-07-03 08:08:073318 for (auto ssrc : ssrcs) {
Henrik Boström8dfc90f2022-09-02 07:39:293319 std::string stream_id = "" + std::to_string(ssrc);
Eldar Relloc07e9042020-07-03 08:08:073320 RTCRemoteInboundRtpStreamStats expected_remote_inbound_rtp(
Danil Chapovalovec2670e2023-04-12 11:11:213321 "RI" + MediaTypeCharStr() + stream_id, kReportBlockTimestampUtc);
Eldar Relloc07e9042020-07-03 08:08:073322 expected_remote_inbound_rtp.ssrc = ssrc;
Di Wu86f04ad2021-03-01 07:36:033323 expected_remote_inbound_rtp.fraction_lost =
3324 static_cast<double>(kFractionLost) / (1 << 8);
Henrik Boström8dfc90f2022-09-02 07:39:293325 expected_remote_inbound_rtp.kind = MediaTypeKind();
Eldar Relloc07e9042020-07-03 08:08:073326 expected_remote_inbound_rtp.transport_id =
Henrik Boström8dfc90f2022-09-02 07:39:293327 "TTransportName1"; // 1 for RTP (we have no RTCP
3328 // transport)
Eldar Relloc07e9042020-07-03 08:08:073329 expected_remote_inbound_rtp.packets_lost = 7;
Henrik Boströmb43e3bb2022-09-26 10:36:443330 expected_remote_inbound_rtp.local_id =
3331 "OTTransportName1" + MediaTypeCharStr() + stream_id;
Danil Chapovalovec2670e2023-04-12 11:11:213332 expected_remote_inbound_rtp.round_trip_time =
3333 kRoundTripTimeSample2.seconds<double>();
Di Wu88a51b22021-03-01 19:22:063334 expected_remote_inbound_rtp.total_round_trip_time =
Danil Chapovalovec2670e2023-04-12 11:11:213335 (kRoundTripTimeSample1 + kRoundTripTimeSample2).seconds<double>();
Di Wu88a51b22021-03-01 19:22:063336 expected_remote_inbound_rtp.round_trip_time_measurements = 2;
Artem Titov880fa812021-07-30 20:30:233337 // This test does not set up RTCCodecStats, so `codec_id` and `jitter` are
Eldar Relloc07e9042020-07-03 08:08:073338 // expected to be missing. These are tested separately.
Henrik Boström883eefc2019-05-27 11:40:253339
Eldar Relloc07e9042020-07-03 08:08:073340 ASSERT_TRUE(report->Get(expected_remote_inbound_rtp.id()));
3341 EXPECT_EQ(report->Get(expected_remote_inbound_rtp.id())
3342 ->cast_to<RTCRemoteInboundRtpStreamStats>(),
3343 expected_remote_inbound_rtp);
3344 EXPECT_TRUE(report->Get(*expected_remote_inbound_rtp.transport_id));
3345 ASSERT_TRUE(report->Get(*expected_remote_inbound_rtp.local_id));
3346 // Lookup works in both directions.
3347 EXPECT_EQ(*report->Get(*expected_remote_inbound_rtp.local_id)
Philipp Hancke1f98b462023-03-07 08:53:593348 ->cast_to<RTCOutboundRtpStreamStats>()
Eldar Relloc07e9042020-07-03 08:08:073349 .remote_id,
3350 expected_remote_inbound_rtp.id());
3351 }
Henrik Boström883eefc2019-05-27 11:40:253352}
3353
3354TEST_P(RTCStatsCollectorTestWithParamKind,
Henrik Boströma3a3b6d2022-11-22 08:56:493355 RTCRemoteInboundRtpStreamStatsRttMissingBeforeMeasurement) {
Danil Chapovalovec2670e2023-04-12 11:11:213356 constexpr Timestamp kReportBlockTimestampUtc = Timestamp::Micros(123456789);
Henrik Boströma3a3b6d2022-11-22 08:56:493357
Danil Chapovalovec2670e2023-04-12 11:11:213358 rtcp::ReportBlock report_block;
Henrik Boströma3a3b6d2022-11-22 08:56:493359 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
3360 // `source_ssrc`, "SSRC of the RTP packet sender".
Danil Chapovalovec2670e2023-04-12 11:11:213361 report_block.SetMediaSsrc(12);
Henrik Boströma3a3b6d2022-11-22 08:56:493362 ReportBlockData report_block_data; // AddRoundTripTimeSample() not called.
Danil Chapovalovec2670e2023-04-12 11:11:213363 report_block_data.SetReportBlock(0, report_block, kReportBlockTimestampUtc);
Henrik Boströma3a3b6d2022-11-22 08:56:493364
3365 AddSenderInfoAndMediaChannel("TransportName", {report_block_data},
3366 absl::nullopt);
3367
3368 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3369
3370 std::string remote_inbound_rtp_id = "RI" + MediaTypeCharStr() + "12";
3371 ASSERT_TRUE(report->Get(remote_inbound_rtp_id));
3372 auto& remote_inbound_rtp = report->Get(remote_inbound_rtp_id)
3373 ->cast_to<RTCRemoteInboundRtpStreamStats>();
3374
Henrik Boströmed1d0842024-01-19 10:27:313375 EXPECT_TRUE(remote_inbound_rtp.round_trip_time_measurements.has_value());
Henrik Boströma3a3b6d2022-11-22 08:56:493376 EXPECT_EQ(0, *remote_inbound_rtp.round_trip_time_measurements);
Henrik Boströmed1d0842024-01-19 10:27:313377 EXPECT_FALSE(remote_inbound_rtp.round_trip_time.has_value());
Henrik Boströma3a3b6d2022-11-22 08:56:493378}
3379
3380TEST_P(RTCStatsCollectorTestWithParamKind,
Henrik Boström883eefc2019-05-27 11:40:253381 RTCRemoteInboundRtpStreamStatsWithTimestampFromReportBlock) {
Danil Chapovalovec2670e2023-04-12 11:11:213382 const Timestamp kReportBlockTimestampUtc = Timestamp::Micros(123456789);
3383 fake_clock_.SetTime(kReportBlockTimestampUtc);
Henrik Boström883eefc2019-05-27 11:40:253384
Danil Chapovalovec2670e2023-04-12 11:11:213385 rtcp::ReportBlock report_block;
Henrik Boström8605fbf2019-06-24 14:44:513386 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
Artem Titov880fa812021-07-30 20:30:233387 // `source_ssrc`, "SSRC of the RTP packet sender".
Danil Chapovalovec2670e2023-04-12 11:11:213388 report_block.SetMediaSsrc(12);
Henrik Boström883eefc2019-05-27 11:40:253389 ReportBlockData report_block_data;
Danil Chapovalovec2670e2023-04-12 11:11:213390 report_block_data.SetReportBlock(0, report_block, kReportBlockTimestampUtc);
Henrik Boström883eefc2019-05-27 11:40:253391
Eldar Relloc07e9042020-07-03 08:08:073392 AddSenderInfoAndMediaChannel("TransportName", {report_block_data},
Henrik Boström883eefc2019-05-27 11:40:253393 absl::nullopt);
3394
3395 // Advance time, it should be OK to have fresher reports than report blocks.
Danil Chapovalov0c626af2020-02-10 10:16:003396 fake_clock_.AdvanceTime(TimeDelta::Micros(1234));
Henrik Boström883eefc2019-05-27 11:40:253397
3398 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3399
Henrik Boström8dfc90f2022-09-02 07:39:293400 std::string remote_inbound_rtp_id = "RI" + MediaTypeCharStr() + "12";
Henrik Boström883eefc2019-05-27 11:40:253401 ASSERT_TRUE(report->Get(remote_inbound_rtp_id));
3402 auto& remote_inbound_rtp = report->Get(remote_inbound_rtp_id)
3403 ->cast_to<RTCRemoteInboundRtpStreamStats>();
3404
3405 // Even though the report time is different, the remote-inbound-rtp timestamp
3406 // is of the time that the report block was received.
Danil Chapovalovec2670e2023-04-12 11:11:213407 EXPECT_EQ(report->timestamp(),
3408 kReportBlockTimestampUtc + TimeDelta::Micros(1234));
3409 EXPECT_EQ(remote_inbound_rtp.timestamp(), kReportBlockTimestampUtc);
Henrik Boström883eefc2019-05-27 11:40:253410}
3411
3412TEST_P(RTCStatsCollectorTestWithParamKind,
3413 RTCRemoteInboundRtpStreamStatsWithCodecBasedMembers) {
Danil Chapovalovec2670e2023-04-12 11:11:213414 const Timestamp kReportBlockTimestampUtc = Timestamp::Micros(123456789);
3415 fake_clock_.SetTime(kReportBlockTimestampUtc);
Henrik Boström883eefc2019-05-27 11:40:253416
Danil Chapovalovec2670e2023-04-12 11:11:213417 rtcp::ReportBlock report_block;
Henrik Boström8605fbf2019-06-24 14:44:513418 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
Artem Titov880fa812021-07-30 20:30:233419 // `source_ssrc`, "SSRC of the RTP packet sender".
Danil Chapovalovec2670e2023-04-12 11:11:213420 report_block.SetMediaSsrc(12);
3421 report_block.SetJitter(5000);
Henrik Boström883eefc2019-05-27 11:40:253422 ReportBlockData report_block_data;
Danil Chapovalovec2670e2023-04-12 11:11:213423 report_block_data.SetReportBlock(0, report_block, kReportBlockTimestampUtc);
Henrik Boström883eefc2019-05-27 11:40:253424
3425 RtpCodecParameters codec;
3426 codec.payload_type = 3;
3427 codec.kind = media_type_;
3428 codec.clock_rate = 1000;
3429
Eldar Relloc07e9042020-07-03 08:08:073430 AddSenderInfoAndMediaChannel("TransportName", {report_block_data}, codec);
Henrik Boström883eefc2019-05-27 11:40:253431
3432 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3433
Henrik Boström8dfc90f2022-09-02 07:39:293434 std::string remote_inbound_rtp_id = "RI" + MediaTypeCharStr() + "12";
Henrik Boström883eefc2019-05-27 11:40:253435 ASSERT_TRUE(report->Get(remote_inbound_rtp_id));
3436 auto& remote_inbound_rtp = report->Get(remote_inbound_rtp_id)
3437 ->cast_to<RTCRemoteInboundRtpStreamStats>();
3438
Henrik Boströmed1d0842024-01-19 10:27:313439 EXPECT_TRUE(remote_inbound_rtp.codec_id.has_value());
Henrik Boström883eefc2019-05-27 11:40:253440 EXPECT_TRUE(report->Get(*remote_inbound_rtp.codec_id));
3441
Henrik Boströmed1d0842024-01-19 10:27:313442 EXPECT_TRUE(remote_inbound_rtp.jitter.has_value());
Henrik Boström883eefc2019-05-27 11:40:253443 // The jitter (in seconds) is the report block's jitter divided by the codec's
3444 // clock rate.
3445 EXPECT_EQ(5.0, *remote_inbound_rtp.jitter);
3446}
3447
3448TEST_P(RTCStatsCollectorTestWithParamKind,
3449 RTCRemoteInboundRtpStreamStatsWithRtcpTransport) {
Danil Chapovalovec2670e2023-04-12 11:11:213450 const Timestamp kReportBlockTimestampUtc = Timestamp::Micros(123456789);
3451 fake_clock_.SetTime(kReportBlockTimestampUtc);
Henrik Boström883eefc2019-05-27 11:40:253452
Danil Chapovalovec2670e2023-04-12 11:11:213453 rtcp::ReportBlock report_block;
Henrik Boström8605fbf2019-06-24 14:44:513454 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
Artem Titov880fa812021-07-30 20:30:233455 // `source_ssrc`, "SSRC of the RTP packet sender".
Danil Chapovalovec2670e2023-04-12 11:11:213456 report_block.SetMediaSsrc(12);
Henrik Boström883eefc2019-05-27 11:40:253457 ReportBlockData report_block_data;
Danil Chapovalovec2670e2023-04-12 11:11:213458 report_block_data.SetReportBlock(0, report_block, kReportBlockTimestampUtc);
Henrik Boström883eefc2019-05-27 11:40:253459
3460 cricket::TransportChannelStats rtp_transport_channel_stats;
3461 rtp_transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
Mirko Bonadei9f6808b2021-05-21 18:46:093462 rtp_transport_channel_stats.dtls_state = DtlsTransportState::kNew;
Henrik Boström883eefc2019-05-27 11:40:253463 cricket::TransportChannelStats rtcp_transport_channel_stats;
3464 rtcp_transport_channel_stats.component =
3465 cricket::ICE_CANDIDATE_COMPONENT_RTCP;
Mirko Bonadei9f6808b2021-05-21 18:46:093466 rtcp_transport_channel_stats.dtls_state = DtlsTransportState::kNew;
Henrik Boström883eefc2019-05-27 11:40:253467 pc_->SetTransportStats("TransportName", {rtp_transport_channel_stats,
3468 rtcp_transport_channel_stats});
Eldar Relloc07e9042020-07-03 08:08:073469 AddSenderInfoAndMediaChannel("TransportName", {report_block_data},
Henrik Boström883eefc2019-05-27 11:40:253470 absl::nullopt);
3471
3472 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3473
Henrik Boström8dfc90f2022-09-02 07:39:293474 std::string remote_inbound_rtp_id = "RI" + MediaTypeCharStr() + "12";
Henrik Boström883eefc2019-05-27 11:40:253475 ASSERT_TRUE(report->Get(remote_inbound_rtp_id));
3476 auto& remote_inbound_rtp = report->Get(remote_inbound_rtp_id)
3477 ->cast_to<RTCRemoteInboundRtpStreamStats>();
3478
Henrik Boströmed1d0842024-01-19 10:27:313479 EXPECT_TRUE(remote_inbound_rtp.transport_id.has_value());
Henrik Boström8dfc90f2022-09-02 07:39:293480 EXPECT_EQ("TTransportName2", // 2 for RTCP
Henrik Boström883eefc2019-05-27 11:40:253481 *remote_inbound_rtp.transport_id);
3482 EXPECT_TRUE(report->Get(*remote_inbound_rtp.transport_id));
3483}
3484
Mirko Bonadei1b575412019-09-23 06:34:503485INSTANTIATE_TEST_SUITE_P(All,
Henrik Boström883eefc2019-05-27 11:40:253486 RTCStatsCollectorTestWithParamKind,
3487 ::testing::Values(cricket::MEDIA_TYPE_AUDIO, // "/0"
3488 cricket::MEDIA_TYPE_VIDEO)); // "/1"
3489
Alessio Bazzicaf7b1b952021-03-23 16:23:043490// Checks that no remote outbound stats are collected if not available in
3491// `VoiceMediaInfo`.
3492TEST_F(RTCStatsCollectorTest,
3493 RTCRemoteOutboundRtpAudioStreamStatsNotCollected) {
3494 ExampleStatsGraph graph =
3495 SetupExampleStatsVoiceGraph(/*add_remote_outbound_stats=*/false);
3496 EXPECT_FALSE(graph.full_report->Get(graph.remote_outbound_rtp_id));
3497 // Also check that no other remote outbound report is created (in case the
3498 // expected ID is incorrect).
3499 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3500 ASSERT_NE(report->begin(), report->end())
3501 << "No reports have been generated.";
3502 for (const auto& stats : *report) {
3503 SCOPED_TRACE(stats.id());
3504 EXPECT_NE(stats.type(), RTCRemoteOutboundRtpStreamStats::kType);
3505 }
3506}
3507
3508// Checks that the remote outbound stats are collected when available in
3509// `VoiceMediaInfo`.
3510TEST_F(RTCStatsCollectorTest, RTCRemoteOutboundRtpAudioStreamStatsCollected) {
3511 ExampleStatsGraph graph =
3512 SetupExampleStatsVoiceGraph(/*add_remote_outbound_stats=*/true);
3513 ASSERT_TRUE(graph.full_report->Get(graph.remote_outbound_rtp_id));
3514 const auto& remote_outbound_rtp =
3515 graph.full_report->Get(graph.remote_outbound_rtp_id)
3516 ->cast_to<RTCRemoteOutboundRtpStreamStats>();
Philipp Hanckeb81823a2023-01-04 14:17:423517 EXPECT_EQ(remote_outbound_rtp.timestamp(),
3518 Timestamp::Millis(kRemoteOutboundStatsTimestampMs));
Alessio Bazzicaf7b1b952021-03-23 16:23:043519 EXPECT_FLOAT_EQ(*remote_outbound_rtp.remote_timestamp,
3520 static_cast<double>(kRemoteOutboundStatsRemoteTimestampMs));
3521 EXPECT_EQ(*remote_outbound_rtp.packets_sent, kRemoteOutboundStatsPacketsSent);
3522 EXPECT_EQ(*remote_outbound_rtp.bytes_sent, kRemoteOutboundStatsBytesSent);
3523 EXPECT_EQ(*remote_outbound_rtp.reports_sent,
3524 kRemoteOutboundStatsReportsCount);
3525}
3526
Henrik Boström646fda02019-05-22 13:49:423527TEST_F(RTCStatsCollectorTest,
3528 RTCVideoSourceStatsNotCollectedForSenderWithoutTrack) {
3529 const uint32_t kSsrc = 4;
3530 const int kAttachmentId = 42;
3531
3532 cricket::VideoMediaInfo video_media_info;
3533 video_media_info.senders.push_back(cricket::VideoSenderInfo());
3534 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3535 video_media_info.senders[0].local_stats[0].ssrc = kSsrc;
Byoungchan Leeefe46b62021-11-10 02:23:563536 video_media_info.senders[0].framerate_input = 29.0;
Tommi19015512022-02-02 10:49:353537 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström646fda02019-05-22 13:49:423538
3539 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
3540 cricket::MEDIA_TYPE_VIDEO, /*track=*/nullptr, kSsrc, kAttachmentId, {});
Tommi6589def2022-02-17 22:36:473541 EXPECT_CALL(*sender, Stop());
3542 EXPECT_CALL(*sender, SetMediaChannel(_));
Henrik Boström646fda02019-05-22 13:49:423543 pc_->AddSender(sender);
3544
3545 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Henrik Boström8dfc90f2022-09-02 07:39:293546 EXPECT_FALSE(report->Get("SV42"));
Henrik Boström646fda02019-05-22 13:49:423547}
3548
Taylor Brandstetter64851c02021-06-24 20:32:503549// Test collecting echo return loss stats from the audio processor attached to
3550// the track, rather than the voice sender info.
3551TEST_F(RTCStatsCollectorTest, CollectEchoReturnLossFromTrackAudioProcessor) {
3552 rtc::scoped_refptr<MediaStream> local_stream =
3553 MediaStream::Create("LocalStreamId");
3554 pc_->mutable_local_streams()->AddStream(local_stream);
3555
3556 // Local audio track
3557 rtc::scoped_refptr<MediaStreamTrackInterface> local_audio_track =
3558 CreateFakeTrack(cricket::MEDIA_TYPE_AUDIO, "LocalAudioTrackID",
3559 MediaStreamTrackInterface::kEnded,
3560 /*create_fake_audio_processor=*/true);
Harald Alvestrand2f7ad282022-04-21 11:35:433561 local_stream->AddTrack(rtc::scoped_refptr<AudioTrackInterface>(
3562 static_cast<AudioTrackInterface*>(local_audio_track.get())));
Taylor Brandstetter64851c02021-06-24 20:32:503563
3564 cricket::VoiceSenderInfo voice_sender_info_ssrc1;
3565 voice_sender_info_ssrc1.local_stats.push_back(cricket::SsrcSenderInfo());
3566 voice_sender_info_ssrc1.local_stats[0].ssrc = 1;
3567
3568 stats_->CreateMockRtpSendersReceiversAndChannels(
3569 {std::make_pair(local_audio_track.get(), voice_sender_info_ssrc1)}, {},
3570 {}, {}, {local_stream->id()}, {});
3571
3572 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3573
Philipp Hanckeb81823a2023-01-04 14:17:423574 RTCAudioSourceStats expected_audio("SA11", report->timestamp());
Taylor Brandstetter64851c02021-06-24 20:32:503575 expected_audio.track_identifier = "LocalAudioTrackID";
3576 expected_audio.kind = "audio";
3577 expected_audio.audio_level = 0;
3578 expected_audio.total_audio_energy = 0;
3579 expected_audio.total_samples_duration = 0;
3580 expected_audio.echo_return_loss = 2.0;
3581 expected_audio.echo_return_loss_enhancement = 3.0;
3582
3583 ASSERT_TRUE(report->Get(expected_audio.id()));
3584 EXPECT_EQ(report->Get(expected_audio.id())->cast_to<RTCAudioSourceStats>(),
3585 expected_audio);
3586}
3587
Henrik Boström5b3541f2018-03-19 12:52:563588TEST_F(RTCStatsCollectorTest, GetStatsWithSenderSelector) {
3589 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
3590 // Expected stats graph when filtered by sender:
3591 //
Henrik Boström646fda02019-05-22 13:49:423592 // media-source
Henrik Boström4e231ee2023-05-24 09:24:133593 // ^
3594 // |
3595 // +--------- outbound-rtp
3596 // | |
3597 // v v
3598 // codec (send) transport
Henrik Boström5b3541f2018-03-19 12:52:563599 rtc::scoped_refptr<const RTCStatsReport> sender_report =
3600 stats_->GetStatsReportWithSenderSelector(graph.sender);
3601 EXPECT_TRUE(sender_report);
Philipp Hanckeb81823a2023-01-04 14:17:423602 EXPECT_EQ(sender_report->timestamp(), graph.full_report->timestamp());
Henrik Boström4e231ee2023-05-24 09:24:133603 EXPECT_EQ(sender_report->size(), 4u);
Henrik Boström5b3541f2018-03-19 12:52:563604 EXPECT_TRUE(sender_report->Get(graph.send_codec_id));
3605 EXPECT_FALSE(sender_report->Get(graph.recv_codec_id));
3606 EXPECT_TRUE(sender_report->Get(graph.outbound_rtp_id));
3607 EXPECT_FALSE(sender_report->Get(graph.inbound_rtp_id));
3608 EXPECT_TRUE(sender_report->Get(graph.transport_id));
Henrik Boström5b3541f2018-03-19 12:52:563609 EXPECT_FALSE(sender_report->Get(graph.peer_connection_id));
Henrik Boström646fda02019-05-22 13:49:423610 EXPECT_TRUE(sender_report->Get(graph.media_source_id));
Henrik Boström5b3541f2018-03-19 12:52:563611}
3612
3613TEST_F(RTCStatsCollectorTest, GetStatsWithReceiverSelector) {
3614 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
3615 // Expected stats graph when filtered by receiver:
3616 //
Henrik Boström4e231ee2023-05-24 09:24:133617 //
3618 //
3619 // inbound-rtp
Henrik Boström646fda02019-05-22 13:49:423620 // | |
3621 // v v
3622 // transport codec (recv)
Henrik Boström5b3541f2018-03-19 12:52:563623 rtc::scoped_refptr<const RTCStatsReport> receiver_report =
3624 stats_->GetStatsReportWithReceiverSelector(graph.receiver);
3625 EXPECT_TRUE(receiver_report);
Henrik Boström4e231ee2023-05-24 09:24:133626 EXPECT_EQ(receiver_report->size(), 3u);
Philipp Hanckeb81823a2023-01-04 14:17:423627 EXPECT_EQ(receiver_report->timestamp(), graph.full_report->timestamp());
Henrik Boström5b3541f2018-03-19 12:52:563628 EXPECT_FALSE(receiver_report->Get(graph.send_codec_id));
3629 EXPECT_TRUE(receiver_report->Get(graph.recv_codec_id));
3630 EXPECT_FALSE(receiver_report->Get(graph.outbound_rtp_id));
3631 EXPECT_TRUE(receiver_report->Get(graph.inbound_rtp_id));
3632 EXPECT_TRUE(receiver_report->Get(graph.transport_id));
Henrik Boström5b3541f2018-03-19 12:52:563633 EXPECT_FALSE(receiver_report->Get(graph.peer_connection_id));
Henrik Boström646fda02019-05-22 13:49:423634 EXPECT_FALSE(receiver_report->Get(graph.media_source_id));
Henrik Boström5b3541f2018-03-19 12:52:563635}
3636
3637TEST_F(RTCStatsCollectorTest, GetStatsWithNullSenderSelector) {
3638 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
3639 rtc::scoped_refptr<const RTCStatsReport> empty_report =
3640 stats_->GetStatsReportWithSenderSelector(nullptr);
3641 EXPECT_TRUE(empty_report);
Philipp Hanckeb81823a2023-01-04 14:17:423642 EXPECT_EQ(empty_report->timestamp(), graph.full_report->timestamp());
Henrik Boström5b3541f2018-03-19 12:52:563643 EXPECT_EQ(empty_report->size(), 0u);
3644}
3645
3646TEST_F(RTCStatsCollectorTest, GetStatsWithNullReceiverSelector) {
3647 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
3648 rtc::scoped_refptr<const RTCStatsReport> empty_report =
3649 stats_->GetStatsReportWithReceiverSelector(nullptr);
3650 EXPECT_TRUE(empty_report);
Philipp Hanckeb81823a2023-01-04 14:17:423651 EXPECT_EQ(empty_report->timestamp(), graph.full_report->timestamp());
Henrik Boström5b3541f2018-03-19 12:52:563652 EXPECT_EQ(empty_report->size(), 0u);
3653}
3654
Henrik Boström5ed4da72022-12-24 10:20:123655// Before SetLocalDescription() senders don't have an SSRC.
3656// To simulate this case we create a mock sender with SSRC=0.
3657TEST_F(RTCStatsCollectorTest, RtpIsMissingWhileSsrcIsZero) {
Harald Alvestrand89061872018-01-02 13:08:343658 rtc::scoped_refptr<MediaStreamTrackInterface> track =
3659 CreateFakeTrack(cricket::MEDIA_TYPE_AUDIO, "audioTrack",
3660 MediaStreamTrackInterface::kLive);
Steve Anton57858b32018-02-15 23:19:503661 rtc::scoped_refptr<MockRtpSenderInternal> sender =
Henrik Boström646fda02019-05-22 13:49:423662 CreateMockSender(cricket::MEDIA_TYPE_AUDIO, track, 0, 49, {});
Tommi6589def2022-02-17 22:36:473663 EXPECT_CALL(*sender, Stop());
Steve Anton5b387312018-02-03 00:00:203664 pc_->AddSender(sender);
3665
3666 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3667
Philipp Hancke1f98b462023-03-07 08:53:593668 auto outbound_rtps = report->GetStatsOfType<RTCOutboundRtpStreamStats>();
Henrik Boström5ed4da72022-12-24 10:20:123669 EXPECT_TRUE(outbound_rtps.empty());
Harald Alvestrand89061872018-01-02 13:08:343670}
3671
Henrik Boström5ed4da72022-12-24 10:20:123672// We may also be in a case where the SSRC has been assigned but no
3673// `voice_sender_info` stats exist yet.
3674TEST_F(RTCStatsCollectorTest, DoNotCrashIfSsrcIsKnownButInfosAreStillMissing) {
Harald Alvestrand76d29522018-01-30 13:43:293675 rtc::scoped_refptr<MediaStreamTrackInterface> track =
3676 CreateFakeTrack(cricket::MEDIA_TYPE_AUDIO, "audioTrack",
3677 MediaStreamTrackInterface::kLive);
Steve Anton57858b32018-02-15 23:19:503678 rtc::scoped_refptr<MockRtpSenderInternal> sender =
Henrik Boström646fda02019-05-22 13:49:423679 CreateMockSender(cricket::MEDIA_TYPE_AUDIO, track, 4711, 49, {});
Tommi6589def2022-02-17 22:36:473680 EXPECT_CALL(*sender, Stop());
Steve Anton5b387312018-02-03 00:00:203681 pc_->AddSender(sender);
3682
Harald Alvestrand76d29522018-01-30 13:43:293683 // We do not generate any matching voice_sender_info stats.
Steve Anton5b387312018-02-03 00:00:203684 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3685
Philipp Hancke1f98b462023-03-07 08:53:593686 auto outbound_rtps = report->GetStatsOfType<RTCOutboundRtpStreamStats>();
Henrik Boström5ed4da72022-12-24 10:20:123687 EXPECT_TRUE(outbound_rtps.empty());
Harald Alvestrand76d29522018-01-30 13:43:293688}
3689
Taylor Brandstetter87d5a742018-03-06 17:42:253690// Used for test below, to test calling GetStatsReport during a callback.
Taylor Brandstetter25e022f2018-03-08 17:53:473691class RecursiveCallback : public RTCStatsCollectorCallback {
Taylor Brandstetter87d5a742018-03-06 17:42:253692 public:
Taylor Brandstetter25e022f2018-03-08 17:53:473693 explicit RecursiveCallback(RTCStatsCollectorWrapper* stats) : stats_(stats) {}
Taylor Brandstetter87d5a742018-03-06 17:42:253694
3695 void OnStatsDelivered(
3696 const rtc::scoped_refptr<const RTCStatsReport>& report) override {
3697 stats_->GetStatsReport();
3698 called_ = true;
3699 }
3700
3701 bool called() const { return called_; }
3702
3703 private:
3704 RTCStatsCollectorWrapper* stats_;
3705 bool called_ = false;
3706};
3707
3708// Test that nothing bad happens if a callback causes GetStatsReport to be
3709// called again recursively. Regression test for crbug.com/webrtc/8973.
Taylor Brandstetter25e022f2018-03-08 17:53:473710TEST_F(RTCStatsCollectorTest, DoNotCrashWhenGetStatsCalledDuringCallback) {
Niels Möller027c7932022-01-25 12:56:073711 auto callback1 = rtc::make_ref_counted<RecursiveCallback>(stats_.get());
3712 auto callback2 = rtc::make_ref_counted<RecursiveCallback>(stats_.get());
Taylor Brandstetter87d5a742018-03-06 17:42:253713 stats_->stats_collector()->GetStatsReport(callback1);
3714 stats_->stats_collector()->GetStatsReport(callback2);
3715 EXPECT_TRUE_WAIT(callback1->called(), kGetStatsReportTimeoutMs);
3716 EXPECT_TRUE_WAIT(callback2->called(), kGetStatsReportTimeoutMs);
3717}
3718
Steve Anton5b387312018-02-03 00:00:203719class RTCTestStats : public RTCStats {
hbosc82f2e12016-09-05 08:36:503720 public:
Steve Anton5b387312018-02-03 00:00:203721 WEBRTC_RTCSTATS_DECL();
3722
Philipp Hanckeb81823a2023-01-04 14:17:423723 RTCTestStats(const std::string& id, Timestamp timestamp)
Henrik Boströmc0ac4df2024-01-16 10:03:193724 : RTCStats(id, timestamp) {}
Steve Anton5b387312018-02-03 00:00:203725
3726 RTCStatsMember<int32_t> dummy_stat;
3727};
3728
Henrik Boströmc0ac4df2024-01-16 10:03:193729WEBRTC_RTCSTATS_IMPL(RTCTestStats,
3730 RTCStats,
3731 "test-stats",
3732 AttributeInit("dummyStat", &dummy_stat))
Steve Anton5b387312018-02-03 00:00:203733
3734// Overrides the stats collection to verify thread usage and that the resulting
3735// partial reports are merged.
3736class FakeRTCStatsCollector : public RTCStatsCollector,
3737 public RTCStatsCollectorCallback {
3738 public:
3739 static rtc::scoped_refptr<FakeRTCStatsCollector> Create(
3740 PeerConnectionInternal* pc,
3741 int64_t cache_lifetime_us) {
Niels Möllere7cc8832022-01-04 14:20:033742 return rtc::scoped_refptr<FakeRTCStatsCollector>(
3743 new rtc::RefCountedObject<FakeRTCStatsCollector>(pc,
3744 cache_lifetime_us));
Steve Anton5b387312018-02-03 00:00:203745 }
3746
Tomas Gunnarssone6de5ae2021-04-22 16:16:353747 // Since FakeRTCStatsCollector inherits twice from RefCountInterface, once via
3748 // RTCStatsCollector and once via RTCStatsCollectorCallback, scoped_refptr
3749 // will get confused about which AddRef()/Release() methods to call.
3750 // So to remove all doubt, we declare them here again in the class that we
3751 // give to scoped_refptr.
3752 // Satisfying the implementation of these methods and associating them with a
3753 // reference counter, will be done by RefCountedObject.
3754 virtual void AddRef() const = 0;
3755 virtual rtc::RefCountReleaseStatus Release() const = 0;
3756
Steve Anton5b387312018-02-03 00:00:203757 // RTCStatsCollectorCallback implementation.
3758 void OnStatsDelivered(
3759 const rtc::scoped_refptr<const RTCStatsReport>& report) override {
3760 EXPECT_TRUE(signaling_thread_->IsCurrent());
Markus Handell6fcd0f82020-07-07 17:08:533761 MutexLock lock(&lock_);
Steve Anton5b387312018-02-03 00:00:203762 delivered_report_ = report;
3763 }
3764
3765 void VerifyThreadUsageAndResultsMerging() {
3766 GetStatsReport(rtc::scoped_refptr<RTCStatsCollectorCallback>(this));
3767 EXPECT_TRUE_WAIT(HasVerifiedResults(), kGetStatsReportTimeoutMs);
3768 }
3769
3770 bool HasVerifiedResults() {
3771 EXPECT_TRUE(signaling_thread_->IsCurrent());
Markus Handell6fcd0f82020-07-07 17:08:533772 MutexLock lock(&lock_);
Steve Anton5b387312018-02-03 00:00:203773 if (!delivered_report_)
3774 return false;
3775 EXPECT_EQ(produced_on_signaling_thread_, 1);
3776 EXPECT_EQ(produced_on_network_thread_, 1);
3777
3778 EXPECT_TRUE(delivered_report_->Get("SignalingThreadStats"));
3779 EXPECT_TRUE(delivered_report_->Get("NetworkThreadStats"));
3780
3781 produced_on_signaling_thread_ = 0;
3782 produced_on_network_thread_ = 0;
3783 delivered_report_ = nullptr;
3784 return true;
hbosc82f2e12016-09-05 08:36:503785 }
3786
3787 protected:
Steve Anton5b387312018-02-03 00:00:203788 FakeRTCStatsCollector(PeerConnectionInternal* pc, int64_t cache_lifetime)
3789 : RTCStatsCollector(pc, cache_lifetime),
3790 signaling_thread_(pc->signaling_thread()),
3791 worker_thread_(pc->worker_thread()),
3792 network_thread_(pc->network_thread()) {}
3793
Henrik Boström40b030e2019-02-28 08:49:313794 void ProducePartialResultsOnSignalingThreadImpl(
Philipp Hanckeb81823a2023-01-04 14:17:423795 Timestamp timestamp,
Henrik Boström40b030e2019-02-28 08:49:313796 RTCStatsReport* partial_report) override {
Steve Anton5b387312018-02-03 00:00:203797 EXPECT_TRUE(signaling_thread_->IsCurrent());
3798 {
Markus Handell6fcd0f82020-07-07 17:08:533799 MutexLock lock(&lock_);
Steve Anton5b387312018-02-03 00:00:203800 EXPECT_FALSE(delivered_report_);
3801 ++produced_on_signaling_thread_;
3802 }
3803
Henrik Boström40b030e2019-02-28 08:49:313804 partial_report->AddStats(std::unique_ptr<const RTCStats>(
Philipp Hanckeb81823a2023-01-04 14:17:423805 new RTCTestStats("SignalingThreadStats", timestamp)));
Steve Anton5b387312018-02-03 00:00:203806 }
Henrik Boström40b030e2019-02-28 08:49:313807 void ProducePartialResultsOnNetworkThreadImpl(
Philipp Hanckeb81823a2023-01-04 14:17:423808 Timestamp timestamp,
Henrik Boström40b030e2019-02-28 08:49:313809 const std::map<std::string, cricket::TransportStats>&
3810 transport_stats_by_name,
3811 const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
3812 RTCStatsReport* partial_report) override {
Steve Anton5b387312018-02-03 00:00:203813 EXPECT_TRUE(network_thread_->IsCurrent());
3814 {
Markus Handell6fcd0f82020-07-07 17:08:533815 MutexLock lock(&lock_);
Steve Anton5b387312018-02-03 00:00:203816 EXPECT_FALSE(delivered_report_);
3817 ++produced_on_network_thread_;
3818 }
3819
Henrik Boström40b030e2019-02-28 08:49:313820 partial_report->AddStats(std::unique_ptr<const RTCStats>(
Philipp Hanckeb81823a2023-01-04 14:17:423821 new RTCTestStats("NetworkThreadStats", timestamp)));
Steve Anton5b387312018-02-03 00:00:203822 }
3823
3824 private:
3825 rtc::Thread* const signaling_thread_;
3826 rtc::Thread* const worker_thread_;
3827 rtc::Thread* const network_thread_;
3828
Markus Handell6fcd0f82020-07-07 17:08:533829 Mutex lock_;
Steve Anton5b387312018-02-03 00:00:203830 rtc::scoped_refptr<const RTCStatsReport> delivered_report_;
3831 int produced_on_signaling_thread_ = 0;
3832 int produced_on_network_thread_ = 0;
hbosc82f2e12016-09-05 08:36:503833};
3834
Steve Anton5b387312018-02-03 00:00:203835TEST(RTCStatsCollectorTestWithFakeCollector, ThreadUsageAndResultsMerging) {
Niels Möller83830f32022-05-20 07:12:573836 rtc::AutoThread main_thread_;
Niels Möller027c7932022-01-25 12:56:073837 auto pc = rtc::make_ref_counted<FakePeerConnectionForStats>();
Steve Anton5b387312018-02-03 00:00:203838 rtc::scoped_refptr<FakeRTCStatsCollector> stats_collector(
Niels Möllerafb246b2022-04-20 12:26:503839 FakeRTCStatsCollector::Create(pc.get(),
3840 50 * rtc::kNumMicrosecsPerMillisec));
Steve Anton5b387312018-02-03 00:00:203841 stats_collector->VerifyThreadUsageAndResultsMerging();
hbosc82f2e12016-09-05 08:36:503842}
3843
3844} // namespace
3845
hbosd565b732016-08-30 21:04:353846} // namespace webrtc