blob: 5a6ac545ca518808bbbf02e1be1b53eecfa019e2 [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"
Harald Alvestrandc24a2182022-02-23 13:44:5931#include "api/stats/rtc_stats.h"
Steve Anton10542f22019-01-11 17:11:0032#include "api/stats/rtc_stats_report.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3133#include "api/stats/rtcstats_objects.h"
Sebastian Jansson5f83cf02018-05-08 12:52:2234#include "api/units/time_delta.h"
Harald Alvestrandc24a2182022-02-23 13:44:5935#include "api/units/timestamp.h"
36#include "api/video/recordable_encoded_frame.h"
37#include "api/video/video_content_type.h"
38#include "api/video/video_frame.h"
39#include "api/video/video_sink_interface.h"
40#include "api/video/video_source_interface.h"
Henrik Boströmc5f8f802022-10-19 15:50:0941#include "api/video/video_timing.h"
Evan Shrubsole9b235cd2022-12-06 10:09:1042#include "api/video_codecs/scalability_mode.h"
Harald Alvestrandc24a2182022-02-23 13:44:5943#include "common_video/include/quality_limitation_reason.h"
44#include "media/base/media_channel.h"
45#include "modules/audio_processing/include/audio_processing_statistics.h"
Henrik Boström883eefc2019-05-27 11:40:2546#include "modules/rtp_rtcp/include/report_block_data.h"
47#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
Harald Alvestrandc24a2182022-02-23 13:44:5948#include "p2p/base/connection_info.h"
49#include "p2p/base/ice_transport_internal.h"
Steve Anton10542f22019-01-11 17:11:0050#include "p2p/base/p2p_constants.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3151#include "p2p/base/port.h"
Steve Anton10542f22019-01-11 17:11:0052#include "pc/media_stream.h"
Harald Alvestrandc24a2182022-02-23 13:44:5953#include "pc/stream_collection.h"
Harald Alvestrand9e5aeb92022-05-11 09:35:3654#include "pc/test/fake_data_channel_controller.h"
Steve Anton10542f22019-01-11 17:11:0055#include "pc/test/fake_peer_connection_for_stats.h"
56#include "pc/test/mock_data_channel.h"
57#include "pc/test/mock_rtp_receiver_internal.h"
58#include "pc/test/mock_rtp_sender_internal.h"
59#include "pc/test/rtc_stats_obtainer.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3160#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 17:11:0061#include "rtc_base/fake_clock.h"
62#include "rtc_base/fake_ssl_identity.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3163#include "rtc_base/gunit.h"
Harald Alvestrandc24a2182022-02-23 13:44:5964#include "rtc_base/network_constants.h"
65#include "rtc_base/ref_counted_object.h"
66#include "rtc_base/rtc_certificate.h"
67#include "rtc_base/socket_address.h"
68#include "rtc_base/ssl_fingerprint.h"
69#include "rtc_base/ssl_identity.h"
70#include "rtc_base/ssl_stream_adapter.h"
71#include "rtc_base/string_encode.h"
Harald Alvestrand910cdc22020-01-09 11:58:2372#include "rtc_base/strings/json.h"
Markus Handell6fcd0f82020-07-07 17:08:5373#include "rtc_base/synchronization/mutex.h"
Steve Anton10542f22019-01-11 17:11:0074#include "rtc_base/time_utils.h"
Harald Alvestrandc24a2182022-02-23 13:44:5975#include "test/gmock.h"
76#include "test/gtest.h"
hbosd565b732016-08-30 21:04:3577
Alessio Bazzica049e6112021-03-18 11:55:1178using ::testing::_;
Mirko Bonadei6a489f22019-04-09 13:11:1279using ::testing::AtLeast;
80using ::testing::Invoke;
81using ::testing::Return;
hbosd565b732016-08-30 21:04:3582
83namespace webrtc {
84
Artem Titov880fa812021-07-30 20:30:2385// These are used by gtest code, such as if `EXPECT_EQ` fails.
hbosda389e32016-10-25 17:55:0886void PrintTo(const RTCCertificateStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:1287 *os << stats.ToJson();
hbosda389e32016-10-25 17:55:0888}
89
hbos0adb8282016-11-23 10:32:0690void PrintTo(const RTCCodecStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:1291 *os << stats.ToJson();
hbos0adb8282016-11-23 10:32:0692}
93
hbosda389e32016-10-25 17:55:0894void PrintTo(const RTCDataChannelStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:1295 *os << stats.ToJson();
hbosda389e32016-10-25 17:55:0896}
97
98void PrintTo(const RTCIceCandidatePairStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:1299 *os << stats.ToJson();
hbosda389e32016-10-25 17:55:08100}
101
102void PrintTo(const RTCLocalIceCandidateStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:12103 *os << stats.ToJson();
hbosda389e32016-10-25 17:55:08104}
105
106void PrintTo(const RTCRemoteIceCandidateStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:12107 *os << stats.ToJson();
hbosda389e32016-10-25 17:55:08108}
109
110void PrintTo(const RTCPeerConnectionStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:12111 *os << stats.ToJson();
hbosda389e32016-10-25 17:55:08112}
113
Henrik Boström15166b22022-10-19 09:06:58114void PrintTo(const DEPRECATED_RTCMediaStreamStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:12115 *os << stats.ToJson();
hbos09bc1282016-11-08 14:29:22116}
117
Henrik Boström15166b22022-10-19 09:06:58118void PrintTo(const DEPRECATED_RTCMediaStreamTrackStats& stats,
119 ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:12120 *os << stats.ToJson();
hbos09bc1282016-11-08 14:29:22121}
122
hboseeafe942016-11-01 10:00:17123void PrintTo(const RTCInboundRTPStreamStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:12124 *os << stats.ToJson();
hboseeafe942016-11-01 10:00:17125}
126
hbos6ded1902016-11-01 08:50:46127void PrintTo(const RTCOutboundRTPStreamStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:12128 *os << stats.ToJson();
hbos6ded1902016-11-01 08:50:46129}
130
Henrik Boström883eefc2019-05-27 11:40:25131void PrintTo(const RTCRemoteInboundRtpStreamStats& stats, ::std::ostream* os) {
132 *os << stats.ToJson();
133}
134
Henrik Boström646fda02019-05-22 13:49:42135void PrintTo(const RTCAudioSourceStats& stats, ::std::ostream* os) {
136 *os << stats.ToJson();
137}
138
139void PrintTo(const RTCVideoSourceStats& stats, ::std::ostream* os) {
140 *os << stats.ToJson();
141}
142
hbosda389e32016-10-25 17:55:08143void PrintTo(const RTCTransportStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 14:29:12144 *os << stats.ToJson();
hbosda389e32016-10-25 17:55:08145}
146
hbosc82f2e12016-09-05 08:36:50147namespace {
148
149const int64_t kGetStatsReportTimeoutMs = 1000;
150
Alessio Bazzicaf7b1b952021-03-23 16:23:04151// Fake data used by `SetupExampleStatsVoiceGraph()` to fill in remote outbound
152// stats.
153constexpr int64_t kRemoteOutboundStatsTimestampMs = 123;
154constexpr int64_t kRemoteOutboundStatsRemoteTimestampMs = 456;
155constexpr uint32_t kRemoteOutboundStatsPacketsSent = 7u;
156constexpr uint64_t kRemoteOutboundStatsBytesSent = 8u;
157constexpr uint64_t kRemoteOutboundStatsReportsCount = 9u;
158
hbos6ab97ce02016-10-03 21:16:56159struct CertificateInfo {
160 rtc::scoped_refptr<rtc::RTCCertificate> certificate;
161 std::vector<std::string> ders;
162 std::vector<std::string> pems;
163 std::vector<std::string> fingerprints;
164};
165
Harald Alvestranda3dab842018-01-14 08:18:58166// Return the ID for an object of the given type in a report.
167// The object must be present and be unique.
168template <typename T>
169std::string IdForType(const RTCStatsReport* report) {
170 auto stats_of_my_type = report->RTCStatsReport::GetStatsOfType<T>();
171 // We cannot use ASSERT here, since we're within a function.
Mirko Bonadeie12c1fe2018-07-03 10:53:23172 EXPECT_EQ(1U, stats_of_my_type.size())
Harald Alvestranda3dab842018-01-14 08:18:58173 << "Unexpected number of stats of this type";
174 if (stats_of_my_type.size() == 1) {
175 return stats_of_my_type[0]->id();
176 } else {
177 // Return something that is not going to be a valid stas ID.
178 return "Type not found";
179 }
180}
181
hbos6ab97ce02016-10-03 21:16:56182std::unique_ptr<CertificateInfo> CreateFakeCertificateAndInfoFromDers(
183 const std::vector<std::string>& ders) {
184 RTC_CHECK(!ders.empty());
185 std::unique_ptr<CertificateInfo> info(new CertificateInfo());
186 info->ders = ders;
187 for (const std::string& der : ders) {
188 info->pems.push_back(rtc::SSLIdentity::DerToPem(
Yves Gerey665174f2018-06-19 13:03:05189 "CERTIFICATE", reinterpret_cast<const unsigned char*>(der.c_str()),
hbos6ab97ce02016-10-03 21:16:56190 der.length()));
191 }
192 info->certificate =
193 rtc::RTCCertificate::Create(std::unique_ptr<rtc::FakeSSLIdentity>(
Taylor Brandstetterc3928662018-02-23 21:04:51194 new rtc::FakeSSLIdentity(info->pems)));
hbos6ab97ce02016-10-03 21:16:56195 // Strip header/footer and newline characters of PEM strings.
196 for (size_t i = 0; i < info->pems.size(); ++i) {
Steve Anton1c9c9fc2019-02-14 23:13:09197 absl::StrReplaceAll({{"-----BEGIN CERTIFICATE-----", ""},
198 {"-----END CERTIFICATE-----", ""},
199 {"\n", ""}},
200 &info->pems[i]);
hbos6ab97ce02016-10-03 21:16:56201 }
Taylor Brandstetterc3928662018-02-23 21:04:51202 // Fingerprints for the whole certificate chain, starting with leaf
203 // certificate.
Benjamin Wright6c6c9df2018-10-25 08:16:26204 const rtc::SSLCertChain& chain = info->certificate->GetSSLCertificateChain();
Taylor Brandstetterc3928662018-02-23 21:04:51205 std::unique_ptr<rtc::SSLFingerprint> fp;
206 for (size_t i = 0; i < chain.GetSize(); i++) {
Steve Anton4905edb2018-10-16 02:27:44207 fp = rtc::SSLFingerprint::Create("sha-1", chain.Get(i));
Taylor Brandstetterc3928662018-02-23 21:04:51208 EXPECT_TRUE(fp);
209 info->fingerprints.push_back(fp->GetRfc4572Fingerprint());
hbos6ab97ce02016-10-03 21:16:56210 }
211 EXPECT_EQ(info->ders.size(), info->fingerprints.size());
212 return info;
213}
214
hbosab9f6e42016-10-07 09:18:47215std::unique_ptr<cricket::Candidate> CreateFakeCandidate(
216 const std::string& hostname,
217 int port,
218 const std::string& protocol,
Gary Liu37e489c2017-11-21 18:49:36219 const rtc::AdapterType adapter_type,
hbosab9f6e42016-10-07 09:18:47220 const std::string& candidate_type,
Jonas Oreland0d13bbd2022-03-02 10:17:36221 uint32_t priority,
222 const rtc::AdapterType underlying_type_for_vpn =
223 rtc::ADAPTER_TYPE_UNKNOWN) {
hbosab9f6e42016-10-07 09:18:47224 std::unique_ptr<cricket::Candidate> candidate(new cricket::Candidate());
225 candidate->set_address(rtc::SocketAddress(hostname, port));
226 candidate->set_protocol(protocol);
Gary Liu37e489c2017-11-21 18:49:36227 candidate->set_network_type(adapter_type);
Jonas Oreland0d13bbd2022-03-02 10:17:36228 candidate->set_underlying_type_for_vpn(underlying_type_for_vpn);
hbosab9f6e42016-10-07 09:18:47229 candidate->set_type(candidate_type);
230 candidate->set_priority(priority);
Philipp Hancke0e3cd632022-09-27 08:23:09231 // Defaults for testing.
232 candidate->set_foundation("foundationIsAString");
233 candidate->set_username("iceusernamefragment");
hbosab9f6e42016-10-07 09:18:47234 return candidate;
235}
236
Taylor Brandstetter64851c02021-06-24 20:32:50237class FakeAudioProcessor : public AudioProcessorInterface {
238 public:
239 FakeAudioProcessor() {}
240 ~FakeAudioProcessor() {}
241
242 private:
243 AudioProcessorInterface::AudioProcessorStatistics GetStats(
244 bool has_recv_streams) override {
245 AudioProcessorStatistics stats;
246 stats.apm_statistics.echo_return_loss = 2.0;
247 stats.apm_statistics.echo_return_loss_enhancement = 3.0;
248 return stats;
249 }
250};
251
Yves Gerey665174f2018-06-19 13:03:05252class FakeAudioTrackForStats : public MediaStreamTrack<AudioTrackInterface> {
hbos09bc1282016-11-08 14:29:22253 public:
254 static rtc::scoped_refptr<FakeAudioTrackForStats> Create(
255 const std::string& id,
Taylor Brandstetter64851c02021-06-24 20:32:50256 MediaStreamTrackInterface::TrackState state,
257 bool create_fake_audio_processor) {
Niels Möller027c7932022-01-25 12:56:07258 auto audio_track_stats = rtc::make_ref_counted<FakeAudioTrackForStats>(id);
hbos09bc1282016-11-08 14:29:22259 audio_track_stats->set_state(state);
Taylor Brandstetter64851c02021-06-24 20:32:50260 if (create_fake_audio_processor) {
261 audio_track_stats->processor_ =
262 rtc::make_ref_counted<FakeAudioProcessor>();
263 }
hbos09bc1282016-11-08 14:29:22264 return audio_track_stats;
265 }
266
Steve Anton36b29d12017-10-30 16:57:42267 explicit FakeAudioTrackForStats(const std::string& id)
268 : MediaStreamTrack<AudioTrackInterface>(id) {}
hbos09bc1282016-11-08 14:29:22269
270 std::string kind() const override {
271 return MediaStreamTrackInterface::kAudioKind;
272 }
273 webrtc::AudioSourceInterface* GetSource() const override { return nullptr; }
274 void AddSink(webrtc::AudioTrackSinkInterface* sink) override {}
275 void RemoveSink(webrtc::AudioTrackSinkInterface* sink) override {}
hbos9e302742017-01-20 10:47:10276 bool GetSignalLevel(int* level) override { return false; }
hbos09bc1282016-11-08 14:29:22277 rtc::scoped_refptr<AudioProcessorInterface> GetAudioProcessor() override {
Taylor Brandstetter64851c02021-06-24 20:32:50278 return processor_;
hbos09bc1282016-11-08 14:29:22279 }
Taylor Brandstetter64851c02021-06-24 20:32:50280
281 private:
282 rtc::scoped_refptr<FakeAudioProcessor> processor_;
hbos09bc1282016-11-08 14:29:22283};
284
Henrik Boström646fda02019-05-22 13:49:42285class FakeVideoTrackSourceForStats : public VideoTrackSourceInterface {
286 public:
287 static rtc::scoped_refptr<FakeVideoTrackSourceForStats> Create(
288 int input_width,
289 int input_height) {
Niels Möller027c7932022-01-25 12:56:07290 return rtc::make_ref_counted<FakeVideoTrackSourceForStats>(input_width,
291 input_height);
Henrik Boström646fda02019-05-22 13:49:42292 }
293
294 FakeVideoTrackSourceForStats(int input_width, int input_height)
295 : input_width_(input_width), input_height_(input_height) {}
296 ~FakeVideoTrackSourceForStats() override {}
297
298 // VideoTrackSourceInterface
299 bool is_screencast() const override { return false; }
300 absl::optional<bool> needs_denoising() const override { return false; }
301 bool GetStats(VideoTrackSourceInterface::Stats* stats) override {
302 stats->input_width = input_width_;
303 stats->input_height = input_height_;
304 return true;
305 }
306 // MediaSourceInterface (part of VideoTrackSourceInterface)
307 MediaSourceInterface::SourceState state() const override {
308 return MediaSourceInterface::SourceState::kLive;
309 }
310 bool remote() const override { return false; }
311 // NotifierInterface (part of MediaSourceInterface)
312 void RegisterObserver(ObserverInterface* observer) override {}
313 void UnregisterObserver(ObserverInterface* observer) override {}
314 // rtc::VideoSourceInterface<VideoFrame> (part of VideoTrackSourceInterface)
315 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
316 const rtc::VideoSinkWants& wants) override {}
317 void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override {}
Markus Handell6efc14b2020-05-05 18:11:13318 bool SupportsEncodedOutput() const override { return false; }
319 void GenerateKeyFrame() override {}
320 void AddEncodedSink(
321 rtc::VideoSinkInterface<RecordableEncodedFrame>* sink) override {}
322 void RemoveEncodedSink(
323 rtc::VideoSinkInterface<RecordableEncodedFrame>* sink) override {}
Henrik Boström646fda02019-05-22 13:49:42324
325 private:
326 int input_width_;
327 int input_height_;
328};
329
Yves Gerey665174f2018-06-19 13:03:05330class FakeVideoTrackForStats : public MediaStreamTrack<VideoTrackInterface> {
hbos09bc1282016-11-08 14:29:22331 public:
332 static rtc::scoped_refptr<FakeVideoTrackForStats> Create(
333 const std::string& id,
Henrik Boström646fda02019-05-22 13:49:42334 MediaStreamTrackInterface::TrackState state,
335 rtc::scoped_refptr<VideoTrackSourceInterface> source) {
Niels Möller027c7932022-01-25 12:56:07336 auto video_track =
337 rtc::make_ref_counted<FakeVideoTrackForStats>(id, std::move(source));
hbos09bc1282016-11-08 14:29:22338 video_track->set_state(state);
339 return video_track;
340 }
341
Henrik Boström646fda02019-05-22 13:49:42342 FakeVideoTrackForStats(const std::string& id,
343 rtc::scoped_refptr<VideoTrackSourceInterface> source)
344 : MediaStreamTrack<VideoTrackInterface>(id), source_(source) {}
hbos09bc1282016-11-08 14:29:22345
346 std::string kind() const override {
347 return MediaStreamTrackInterface::kVideoKind;
348 }
perkj773be362017-08-01 06:22:01349
350 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
Mirko Bonadeic4dd7302019-02-25 08:12:02351 const rtc::VideoSinkWants& wants) override {}
352 void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override {}
perkj773be362017-08-01 06:22:01353
Henrik Boström646fda02019-05-22 13:49:42354 VideoTrackSourceInterface* GetSource() const override {
355 return source_.get();
356 }
357
358 private:
359 rtc::scoped_refptr<VideoTrackSourceInterface> source_;
hbos09bc1282016-11-08 14:29:22360};
361
hbos84abeb12017-01-16 14:16:44362rtc::scoped_refptr<MediaStreamTrackInterface> CreateFakeTrack(
363 cricket::MediaType media_type,
hbos9e302742017-01-20 10:47:10364 const std::string& track_id,
Taylor Brandstetter64851c02021-06-24 20:32:50365 MediaStreamTrackInterface::TrackState track_state,
366 bool create_fake_audio_processor = false) {
hbos84abeb12017-01-16 14:16:44367 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
Taylor Brandstetter64851c02021-06-24 20:32:50368 return FakeAudioTrackForStats::Create(track_id, track_state,
369 create_fake_audio_processor);
hbos84abeb12017-01-16 14:16:44370 } else {
371 RTC_DCHECK_EQ(media_type, cricket::MEDIA_TYPE_VIDEO);
Henrik Boström646fda02019-05-22 13:49:42372 return FakeVideoTrackForStats::Create(track_id, track_state, nullptr);
hbos84abeb12017-01-16 14:16:44373 }
374}
375
Steve Anton57858b32018-02-15 23:19:50376rtc::scoped_refptr<MockRtpSenderInternal> CreateMockSender(
Henrik Boström646fda02019-05-22 13:49:42377 cricket::MediaType media_type,
378 rtc::scoped_refptr<MediaStreamTrackInterface> track,
Harald Alvestrandc72af932018-01-11 16:18:19379 uint32_t ssrc,
Harald Alvestranda3dab842018-01-14 08:18:58380 int attachment_id,
381 std::vector<std::string> local_stream_ids) {
Henrik Boström646fda02019-05-22 13:49:42382 RTC_DCHECK(!track ||
383 (track->kind() == MediaStreamTrackInterface::kAudioKind &&
384 media_type == cricket::MEDIA_TYPE_AUDIO) ||
385 (track->kind() == MediaStreamTrackInterface::kVideoKind &&
386 media_type == cricket::MEDIA_TYPE_VIDEO));
Niels Möller027c7932022-01-25 12:56:07387 auto sender = rtc::make_ref_counted<MockRtpSenderInternal>();
hbos9e302742017-01-20 10:47:10388 EXPECT_CALL(*sender, track()).WillRepeatedly(Return(track));
389 EXPECT_CALL(*sender, ssrc()).WillRepeatedly(Return(ssrc));
Henrik Boström646fda02019-05-22 13:49:42390 EXPECT_CALL(*sender, media_type()).WillRepeatedly(Return(media_type));
Henrik Boström81aab482022-12-23 17:17:06391 EXPECT_CALL(*sender, GetParameters())
392 .WillRepeatedly(
393 Invoke([s = sender.get()]() { return s->GetParametersInternal(); }));
394 EXPECT_CALL(*sender, GetParametersInternal()).WillRepeatedly(Invoke([ssrc]() {
Yves Gerey665174f2018-06-19 13:03:05395 RtpParameters params;
396 params.encodings.push_back(RtpEncodingParameters());
397 params.encodings[0].ssrc = ssrc;
398 return params;
399 }));
Harald Alvestrandc72af932018-01-11 16:18:19400 EXPECT_CALL(*sender, AttachmentId()).WillRepeatedly(Return(attachment_id));
Harald Alvestranda3dab842018-01-14 08:18:58401 EXPECT_CALL(*sender, stream_ids()).WillRepeatedly(Return(local_stream_ids));
Alessio Bazzica049e6112021-03-18 11:55:11402 EXPECT_CALL(*sender, SetTransceiverAsStopped());
hbos9e302742017-01-20 10:47:10403 return sender;
404}
405
Steve Anton57858b32018-02-15 23:19:50406rtc::scoped_refptr<MockRtpReceiverInternal> CreateMockReceiver(
Mirko Bonadeic61ce0d2017-11-21 16:04:20407 const rtc::scoped_refptr<MediaStreamTrackInterface>& track,
Harald Alvestrandc72af932018-01-11 16:18:19408 uint32_t ssrc,
409 int attachment_id) {
Niels Möller027c7932022-01-25 12:56:07410 auto receiver = rtc::make_ref_counted<MockRtpReceiverInternal>();
hbos9e302742017-01-20 10:47:10411 EXPECT_CALL(*receiver, track()).WillRepeatedly(Return(track));
Harald Alvestranda3dab842018-01-14 08:18:58412 EXPECT_CALL(*receiver, streams())
413 .WillRepeatedly(
414 Return(std::vector<rtc::scoped_refptr<MediaStreamInterface>>({})));
415
Yves Gerey665174f2018-06-19 13:03:05416 EXPECT_CALL(*receiver, media_type())
417 .WillRepeatedly(
418 Return(track->kind() == MediaStreamTrackInterface::kAudioKind
419 ? cricket::MEDIA_TYPE_AUDIO
420 : cricket::MEDIA_TYPE_VIDEO));
421 EXPECT_CALL(*receiver, GetParameters()).WillRepeatedly(Invoke([ssrc]() {
422 RtpParameters params;
423 params.encodings.push_back(RtpEncodingParameters());
424 params.encodings[0].ssrc = ssrc;
425 return params;
426 }));
Harald Alvestrandc72af932018-01-11 16:18:19427 EXPECT_CALL(*receiver, AttachmentId()).WillRepeatedly(Return(attachment_id));
Tommi6589def2022-02-17 22:36:47428 EXPECT_CALL(*receiver, Stop()).WillRepeatedly(Return());
hbos9e302742017-01-20 10:47:10429 return receiver;
430}
431
Steve Anton5b387312018-02-03 00:00:20432class RTCStatsCollectorWrapper {
hbosd565b732016-08-30 21:04:35433 public:
Steve Anton5b387312018-02-03 00:00:20434 explicit RTCStatsCollectorWrapper(
435 rtc::scoped_refptr<FakePeerConnectionForStats> pc)
436 : pc_(pc),
437 stats_collector_(
Niels Möllerafb246b2022-04-20 12:26:50438 RTCStatsCollector::Create(pc.get(),
439 50 * rtc::kNumMicrosecsPerMillisec)) {}
hbosd565b732016-08-30 21:04:35440
Steve Anton5b387312018-02-03 00:00:20441 rtc::scoped_refptr<RTCStatsCollector> stats_collector() {
442 return stats_collector_;
hbosd565b732016-08-30 21:04:35443 }
444
Henrik Boström5b3541f2018-03-19 12:52:56445 rtc::scoped_refptr<const RTCStatsReport> GetStatsReport() {
446 rtc::scoped_refptr<RTCStatsObtainer> callback = RTCStatsObtainer::Create();
447 stats_collector_->GetStatsReport(callback);
448 return WaitForReport(callback);
449 }
450
451 rtc::scoped_refptr<const RTCStatsReport> GetStatsReportWithSenderSelector(
452 rtc::scoped_refptr<RtpSenderInternal> selector) {
453 rtc::scoped_refptr<RTCStatsObtainer> callback = RTCStatsObtainer::Create();
454 stats_collector_->GetStatsReport(selector, callback);
455 return WaitForReport(callback);
456 }
457
458 rtc::scoped_refptr<const RTCStatsReport> GetStatsReportWithReceiverSelector(
459 rtc::scoped_refptr<RtpReceiverInternal> selector) {
460 rtc::scoped_refptr<RTCStatsObtainer> callback = RTCStatsObtainer::Create();
461 stats_collector_->GetStatsReport(selector, callback);
462 return WaitForReport(callback);
463 }
464
Steve Anton5b387312018-02-03 00:00:20465 rtc::scoped_refptr<const RTCStatsReport> GetFreshStatsReport() {
466 stats_collector_->ClearCachedStatsReport();
467 return GetStatsReport();
468 }
469
Henrik Boström5b3541f2018-03-19 12:52:56470 rtc::scoped_refptr<MockRtpSenderInternal> SetupLocalTrackAndSender(
471 cricket::MediaType media_type,
472 const std::string& track_id,
473 uint32_t ssrc,
Henrik Boström646fda02019-05-22 13:49:42474 bool add_stream,
475 int attachment_id) {
Harald Alvestrand89061872018-01-02 13:08:34476 rtc::scoped_refptr<MediaStream> local_stream;
477 if (add_stream) {
Seth Hampson845e8782018-03-02 19:34:10478 local_stream = MediaStream::Create("LocalStreamId");
Steve Anton5b387312018-02-03 00:00:20479 pc_->mutable_local_streams()->AddStream(local_stream);
Harald Alvestrand89061872018-01-02 13:08:34480 }
hbos84abeb12017-01-16 14:16:44481
482 rtc::scoped_refptr<MediaStreamTrackInterface> track;
483 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
hbos9e302742017-01-20 10:47:10484 track = CreateFakeTrack(media_type, track_id,
485 MediaStreamTrackInterface::kLive);
Harald Alvestrand89061872018-01-02 13:08:34486 if (add_stream) {
Harald Alvestrand2f7ad282022-04-21 11:35:43487 local_stream->AddTrack(rtc::scoped_refptr<AudioTrackInterface>(
488 static_cast<AudioTrackInterface*>(track.get())));
Harald Alvestrand89061872018-01-02 13:08:34489 }
hbos84abeb12017-01-16 14:16:44490 } else {
hbos9e302742017-01-20 10:47:10491 track = CreateFakeTrack(media_type, track_id,
492 MediaStreamTrackInterface::kLive);
Harald Alvestrand89061872018-01-02 13:08:34493 if (add_stream) {
Harald Alvestrand2f7ad282022-04-21 11:35:43494 local_stream->AddTrack(rtc::scoped_refptr<VideoTrackInterface>(
495 static_cast<VideoTrackInterface*>(track.get())));
Harald Alvestrand89061872018-01-02 13:08:34496 }
hbos84abeb12017-01-16 14:16:44497 }
498
Steve Anton57858b32018-02-15 23:19:50499 rtc::scoped_refptr<MockRtpSenderInternal> sender =
Henrik Boström646fda02019-05-22 13:49:42500 CreateMockSender(media_type, track, ssrc, attachment_id, {});
Tommi6589def2022-02-17 22:36:47501 EXPECT_CALL(*sender, Stop());
502 EXPECT_CALL(*sender, SetMediaChannel(_));
Steve Anton5b387312018-02-03 00:00:20503 pc_->AddSender(sender);
Henrik Boström5b3541f2018-03-19 12:52:56504 return sender;
hbos84abeb12017-01-16 14:16:44505 }
506
Henrik Boström5b3541f2018-03-19 12:52:56507 rtc::scoped_refptr<MockRtpReceiverInternal> SetupRemoteTrackAndReceiver(
508 cricket::MediaType media_type,
509 const std::string& track_id,
510 const std::string& stream_id,
511 uint32_t ssrc) {
hbos84abeb12017-01-16 14:16:44512 rtc::scoped_refptr<MediaStream> remote_stream =
Henrik Boström5b3541f2018-03-19 12:52:56513 MediaStream::Create(stream_id);
Steve Anton5b387312018-02-03 00:00:20514 pc_->mutable_remote_streams()->AddStream(remote_stream);
hbos84abeb12017-01-16 14:16:44515
516 rtc::scoped_refptr<MediaStreamTrackInterface> track;
517 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
hbos9e302742017-01-20 10:47:10518 track = CreateFakeTrack(media_type, track_id,
519 MediaStreamTrackInterface::kLive);
Harald Alvestrand2f7ad282022-04-21 11:35:43520 remote_stream->AddTrack(rtc::scoped_refptr<AudioTrackInterface>(
521 static_cast<AudioTrackInterface*>(track.get())));
hbos84abeb12017-01-16 14:16:44522 } else {
hbos9e302742017-01-20 10:47:10523 track = CreateFakeTrack(media_type, track_id,
524 MediaStreamTrackInterface::kLive);
Harald Alvestrand2f7ad282022-04-21 11:35:43525 remote_stream->AddTrack(rtc::scoped_refptr<VideoTrackInterface>(
526 static_cast<VideoTrackInterface*>(track.get())));
hbos84abeb12017-01-16 14:16:44527 }
528
Steve Anton57858b32018-02-15 23:19:50529 rtc::scoped_refptr<MockRtpReceiverInternal> receiver =
Harald Alvestrandc72af932018-01-11 16:18:19530 CreateMockReceiver(track, ssrc, 62);
Harald Alvestranda3dab842018-01-14 08:18:58531 EXPECT_CALL(*receiver, streams())
532 .WillRepeatedly(
533 Return(std::vector<rtc::scoped_refptr<MediaStreamInterface>>(
534 {remote_stream})));
Tommi6589def2022-02-17 22:36:47535 EXPECT_CALL(*receiver, SetMediaChannel(_)).WillRepeatedly(Return());
Steve Anton5b387312018-02-03 00:00:20536 pc_->AddReceiver(receiver);
Henrik Boström5b3541f2018-03-19 12:52:56537 return receiver;
hbos84abeb12017-01-16 14:16:44538 }
539
hbos9e302742017-01-20 10:47:10540 // Attaches tracks to peer connections by configuring RTP senders and RTP
541 // receivers according to the tracks' pairings with
542 // |[Voice/Video][Sender/Receiver]Info| and their SSRCs. Local tracks can be
543 // associated with multiple |[Voice/Video]SenderInfo|s, remote tracks can only
544 // be associated with one |[Voice/Video]ReceiverInfo|.
Henrik Boström646fda02019-05-22 13:49:42545 // Senders get assigned attachment ID "ssrc + 10".
hbos9e302742017-01-20 10:47:10546 void CreateMockRtpSendersReceiversAndChannels(
Harald Alvestranda3dab842018-01-14 08:18:58547 std::initializer_list<
548 std::pair<MediaStreamTrackInterface*, cricket::VoiceSenderInfo>>
549 local_audio_track_info_pairs,
550 std::initializer_list<
551 std::pair<MediaStreamTrackInterface*, cricket::VoiceReceiverInfo>>
552 remote_audio_track_info_pairs,
553 std::initializer_list<
554 std::pair<MediaStreamTrackInterface*, cricket::VideoSenderInfo>>
555 local_video_track_info_pairs,
556 std::initializer_list<
557 std::pair<MediaStreamTrackInterface*, cricket::VideoReceiverInfo>>
558 remote_video_track_info_pairs,
559 std::vector<std::string> local_stream_ids,
560 std::vector<rtc::scoped_refptr<MediaStreamInterface>> remote_streams) {
Steve Anton5b387312018-02-03 00:00:20561 cricket::VoiceMediaInfo voice_media_info;
562 cricket::VideoMediaInfo video_media_info;
563
hbos9e302742017-01-20 10:47:10564 // Local audio tracks and voice sender infos
565 for (auto& pair : local_audio_track_info_pairs) {
566 MediaStreamTrackInterface* local_audio_track = pair.first;
567 const cricket::VoiceSenderInfo& voice_sender_info = pair.second;
568 RTC_DCHECK_EQ(local_audio_track->kind(),
569 MediaStreamTrackInterface::kAudioKind);
570
Steve Anton5b387312018-02-03 00:00:20571 voice_media_info.senders.push_back(voice_sender_info);
Steve Anton57858b32018-02-15 23:19:50572 rtc::scoped_refptr<MockRtpSenderInternal> rtp_sender = CreateMockSender(
Henrik Boström646fda02019-05-22 13:49:42573 cricket::MEDIA_TYPE_AUDIO,
Harald Alvestrandc72af932018-01-11 16:18:19574 rtc::scoped_refptr<MediaStreamTrackInterface>(local_audio_track),
Henrik Boström646fda02019-05-22 13:49:42575 voice_sender_info.local_stats[0].ssrc,
576 voice_sender_info.local_stats[0].ssrc + 10, local_stream_ids);
Tomas Gunnarsson16de2162022-01-26 09:21:57577 EXPECT_CALL(*rtp_sender, SetMediaChannel(_)).WillRepeatedly(Return());
Tommi6589def2022-02-17 22:36:47578 EXPECT_CALL(*rtp_sender, Stop());
Steve Anton5b387312018-02-03 00:00:20579 pc_->AddSender(rtp_sender);
hbos9e302742017-01-20 10:47:10580 }
Steve Anton5b387312018-02-03 00:00:20581
hbos9e302742017-01-20 10:47:10582 // Remote audio tracks and voice receiver infos
583 for (auto& pair : remote_audio_track_info_pairs) {
584 MediaStreamTrackInterface* remote_audio_track = pair.first;
585 const cricket::VoiceReceiverInfo& voice_receiver_info = pair.second;
586 RTC_DCHECK_EQ(remote_audio_track->kind(),
587 MediaStreamTrackInterface::kAudioKind);
588
Steve Anton5b387312018-02-03 00:00:20589 voice_media_info.receivers.push_back(voice_receiver_info);
Steve Anton57858b32018-02-15 23:19:50590 rtc::scoped_refptr<MockRtpReceiverInternal> rtp_receiver =
591 CreateMockReceiver(
592 rtc::scoped_refptr<MediaStreamTrackInterface>(remote_audio_track),
Henrik Boström646fda02019-05-22 13:49:42593 voice_receiver_info.local_stats[0].ssrc,
594 voice_receiver_info.local_stats[0].ssrc + 10);
Harald Alvestranda3dab842018-01-14 08:18:58595 EXPECT_CALL(*rtp_receiver, streams())
596 .WillRepeatedly(Return(remote_streams));
Tommi6589def2022-02-17 22:36:47597 EXPECT_CALL(*rtp_receiver, SetMediaChannel(_)).WillRepeatedly(Return());
Steve Anton5b387312018-02-03 00:00:20598 pc_->AddReceiver(rtp_receiver);
hbos9e302742017-01-20 10:47:10599 }
Steve Anton5b387312018-02-03 00:00:20600
hbos9e302742017-01-20 10:47:10601 // Local video tracks and video sender infos
602 for (auto& pair : local_video_track_info_pairs) {
603 MediaStreamTrackInterface* local_video_track = pair.first;
604 const cricket::VideoSenderInfo& video_sender_info = pair.second;
605 RTC_DCHECK_EQ(local_video_track->kind(),
606 MediaStreamTrackInterface::kVideoKind);
607
Steve Anton5b387312018-02-03 00:00:20608 video_media_info.senders.push_back(video_sender_info);
Henrik Boströma0ff50c2020-05-05 13:54:46609 video_media_info.aggregated_senders.push_back(video_sender_info);
Steve Anton57858b32018-02-15 23:19:50610 rtc::scoped_refptr<MockRtpSenderInternal> rtp_sender = CreateMockSender(
Henrik Boström646fda02019-05-22 13:49:42611 cricket::MEDIA_TYPE_VIDEO,
Harald Alvestrandc72af932018-01-11 16:18:19612 rtc::scoped_refptr<MediaStreamTrackInterface>(local_video_track),
Henrik Boström646fda02019-05-22 13:49:42613 video_sender_info.local_stats[0].ssrc,
614 video_sender_info.local_stats[0].ssrc + 10, local_stream_ids);
Tomas Gunnarsson16de2162022-01-26 09:21:57615 EXPECT_CALL(*rtp_sender, SetMediaChannel(_)).WillRepeatedly(Return());
Tommi6589def2022-02-17 22:36:47616 EXPECT_CALL(*rtp_sender, Stop());
Steve Anton5b387312018-02-03 00:00:20617 pc_->AddSender(rtp_sender);
hbos9e302742017-01-20 10:47:10618 }
Steve Anton5b387312018-02-03 00:00:20619
hbos9e302742017-01-20 10:47:10620 // Remote video tracks and video receiver infos
621 for (auto& pair : remote_video_track_info_pairs) {
622 MediaStreamTrackInterface* remote_video_track = pair.first;
623 const cricket::VideoReceiverInfo& video_receiver_info = pair.second;
624 RTC_DCHECK_EQ(remote_video_track->kind(),
625 MediaStreamTrackInterface::kVideoKind);
626
Steve Anton5b387312018-02-03 00:00:20627 video_media_info.receivers.push_back(video_receiver_info);
Steve Anton57858b32018-02-15 23:19:50628 rtc::scoped_refptr<MockRtpReceiverInternal> rtp_receiver =
629 CreateMockReceiver(
630 rtc::scoped_refptr<MediaStreamTrackInterface>(remote_video_track),
Henrik Boström646fda02019-05-22 13:49:42631 video_receiver_info.local_stats[0].ssrc,
632 video_receiver_info.local_stats[0].ssrc + 10);
Harald Alvestranda3dab842018-01-14 08:18:58633 EXPECT_CALL(*rtp_receiver, streams())
634 .WillRepeatedly(Return(remote_streams));
Tommi6589def2022-02-17 22:36:47635 EXPECT_CALL(*rtp_receiver, SetMediaChannel(_)).WillRepeatedly(Return());
Steve Anton5b387312018-02-03 00:00:20636 pc_->AddReceiver(rtp_receiver);
hbos9e302742017-01-20 10:47:10637 }
hbos9e302742017-01-20 10:47:10638
Tommi19015512022-02-02 10:49:35639 pc_->AddVoiceChannel("audio", "transport", voice_media_info);
640 pc_->AddVideoChannel("video", "transport", video_media_info);
hbos9e302742017-01-20 10:47:10641 }
642
hbosd565b732016-08-30 21:04:35643 private:
Henrik Boström5b3541f2018-03-19 12:52:56644 rtc::scoped_refptr<const RTCStatsReport> WaitForReport(
645 rtc::scoped_refptr<RTCStatsObtainer> callback) {
Niels Möllerafb246b2022-04-20 12:26:50646 EXPECT_TRUE_WAIT(callback->report() != nullptr, kGetStatsReportTimeoutMs);
Henrik Boström5b3541f2018-03-19 12:52:56647 int64_t after = rtc::TimeUTCMicros();
648 for (const RTCStats& stats : *callback->report()) {
Alessio Bazzicaf7b1b952021-03-23 16:23:04649 if (stats.type() == RTCRemoteInboundRtpStreamStats::kType ||
650 stats.type() == RTCRemoteOutboundRtpStreamStats::kType) {
651 // Ignore remote timestamps.
652 continue;
653 }
Henrik Boström5b3541f2018-03-19 12:52:56654 EXPECT_LE(stats.timestamp_us(), after);
655 }
656 return callback->report();
657 }
658
Steve Anton5b387312018-02-03 00:00:20659 rtc::scoped_refptr<FakePeerConnectionForStats> pc_;
660 rtc::scoped_refptr<RTCStatsCollector> stats_collector_;
hbosd565b732016-08-30 21:04:35661};
662
Mirko Bonadei6a489f22019-04-09 13:11:12663class RTCStatsCollectorTest : public ::testing::Test {
hbosc82f2e12016-09-05 08:36:50664 public:
665 RTCStatsCollectorTest()
Niels Möller027c7932022-01-25 12:56:07666 : pc_(rtc::make_ref_counted<FakePeerConnectionForStats>()),
Steve Anton5b387312018-02-03 00:00:20667 stats_(new RTCStatsCollectorWrapper(pc_)) {}
hbosc82f2e12016-09-05 08:36:50668
hbos6ab97ce02016-10-03 21:16:56669 void ExpectReportContainsCertificateInfo(
670 const rtc::scoped_refptr<const RTCStatsReport>& report,
hbos23368e12016-12-21 12:29:17671 const CertificateInfo& certinfo) {
672 for (size_t i = 0; i < certinfo.fingerprints.size(); ++i) {
673 RTCCertificateStats expected_certificate_stats(
Henrik Boström8dfc90f2022-09-02 07:39:29674 "CF" + certinfo.fingerprints[i], report->timestamp_us());
hbos23368e12016-12-21 12:29:17675 expected_certificate_stats.fingerprint = certinfo.fingerprints[i];
676 expected_certificate_stats.fingerprint_algorithm = "sha-1";
677 expected_certificate_stats.base64_certificate = certinfo.pems[i];
678 if (i + 1 < certinfo.fingerprints.size()) {
679 expected_certificate_stats.issuer_certificate_id =
Henrik Boström8dfc90f2022-09-02 07:39:29680 "CF" + certinfo.fingerprints[i + 1];
hbos6ab97ce02016-10-03 21:16:56681 }
hbos23368e12016-12-21 12:29:17682 ASSERT_TRUE(report->Get(expected_certificate_stats.id()));
683 EXPECT_EQ(expected_certificate_stats,
Yves Gerey665174f2018-06-19 13:03:05684 report->Get(expected_certificate_stats.id())
685 ->cast_to<RTCCertificateStats>());
hbos6ab97ce02016-10-03 21:16:56686 }
687 }
688
Henrik Boström69d23c92022-09-26 12:13:17689 const RTCCertificateStats* GetCertificateStatsFromFingerprint(
690 const rtc::scoped_refptr<const RTCStatsReport>& report,
691 const std::string& fingerprint) {
692 auto certificates = report->GetStatsOfType<RTCCertificateStats>();
693 for (const auto* certificate : certificates) {
694 if (*certificate->fingerprint == fingerprint) {
695 return certificate;
696 }
697 }
698 return nullptr;
699 }
700
Henrik Boström5b3541f2018-03-19 12:52:56701 struct ExampleStatsGraph {
702 rtc::scoped_refptr<RtpSenderInternal> sender;
703 rtc::scoped_refptr<RtpReceiverInternal> receiver;
704
705 rtc::scoped_refptr<const RTCStatsReport> full_report;
706 std::string send_codec_id;
707 std::string recv_codec_id;
708 std::string outbound_rtp_id;
709 std::string inbound_rtp_id;
Alessio Bazzicaf7b1b952021-03-23 16:23:04710 std::string remote_outbound_rtp_id;
Henrik Boström5b3541f2018-03-19 12:52:56711 std::string transport_id;
712 std::string sender_track_id;
713 std::string receiver_track_id;
714 std::string remote_stream_id;
715 std::string peer_connection_id;
Henrik Boström646fda02019-05-22 13:49:42716 std::string media_source_id;
Henrik Boström5b3541f2018-03-19 12:52:56717 };
718
Alessio Bazzicaf7b1b952021-03-23 16:23:04719 // Sets up the example stats graph (see ASCII art below) for a video only
720 // call. The graph is used for testing the stats selection algorithm (see
721 // https://w3c.github.io/webrtc-pc/#dfn-stats-selection-algorithm).
Henrik Boström5b3541f2018-03-19 12:52:56722 // These tests test the integration of the stats traversal algorithm inside of
723 // RTCStatsCollector. See rtcstatstraveral_unittest.cc for more stats
724 // traversal tests.
725 ExampleStatsGraph SetupExampleStatsGraphForSelectorTests() {
726 ExampleStatsGraph graph;
727
728 // codec (send)
Henrik Boström8dfc90f2022-09-02 07:39:29729 graph.send_codec_id = "COTTransportName1_1";
Henrik Boström5b3541f2018-03-19 12:52:56730 cricket::VideoMediaInfo video_media_info;
731 RtpCodecParameters send_codec;
732 send_codec.payload_type = 1;
733 send_codec.clock_rate = 0;
734 video_media_info.send_codecs.insert(
735 std::make_pair(send_codec.payload_type, send_codec));
736 // codec (recv)
Henrik Boström8dfc90f2022-09-02 07:39:29737 graph.recv_codec_id = "CITTransportName1_2";
Henrik Boström5b3541f2018-03-19 12:52:56738 RtpCodecParameters recv_codec;
739 recv_codec.payload_type = 2;
740 recv_codec.clock_rate = 0;
741 video_media_info.receive_codecs.insert(
742 std::make_pair(recv_codec.payload_type, recv_codec));
743 // outbound-rtp
Henrik Boströmb43e3bb2022-09-26 10:36:44744 graph.outbound_rtp_id = "OTTransportName1V3";
Henrik Boström5b3541f2018-03-19 12:52:56745 video_media_info.senders.push_back(cricket::VideoSenderInfo());
746 video_media_info.senders[0].local_stats.push_back(
747 cricket::SsrcSenderInfo());
748 video_media_info.senders[0].local_stats[0].ssrc = 3;
749 video_media_info.senders[0].codec_payload_type = send_codec.payload_type;
Henrik Boströma0ff50c2020-05-05 13:54:46750 video_media_info.aggregated_senders.push_back(video_media_info.senders[0]);
Henrik Boström5b3541f2018-03-19 12:52:56751 // inbound-rtp
Henrik Boströmb43e3bb2022-09-26 10:36:44752 graph.inbound_rtp_id = "ITTransportName1V4";
Henrik Boström5b3541f2018-03-19 12:52:56753 video_media_info.receivers.push_back(cricket::VideoReceiverInfo());
754 video_media_info.receivers[0].local_stats.push_back(
755 cricket::SsrcReceiverInfo());
756 video_media_info.receivers[0].local_stats[0].ssrc = 4;
757 video_media_info.receivers[0].codec_payload_type = recv_codec.payload_type;
758 // transport
Henrik Boström8dfc90f2022-09-02 07:39:29759 graph.transport_id = "TTransportName1";
Tommi19015512022-02-02 10:49:35760 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström5b3541f2018-03-19 12:52:56761 // track (sender)
762 graph.sender = stats_->SetupLocalTrackAndSender(
Henrik Boström646fda02019-05-22 13:49:42763 cricket::MEDIA_TYPE_VIDEO, "LocalVideoTrackID", 3, false, 50);
Henrik Boström8dfc90f2022-09-02 07:39:29764 graph.sender_track_id =
765 "DEPRECATED_TO" + rtc::ToString(graph.sender->AttachmentId());
Henrik Boström5b3541f2018-03-19 12:52:56766 // track (receiver) and stream (remote stream)
767 graph.receiver = stats_->SetupRemoteTrackAndReceiver(
768 cricket::MEDIA_TYPE_VIDEO, "RemoteVideoTrackID", "RemoteStreamId", 4);
Henrik Boström8dfc90f2022-09-02 07:39:29769 graph.receiver_track_id =
770 "DEPRECATED_TI" + rtc::ToString(graph.receiver->AttachmentId());
771 graph.remote_stream_id = "DEPRECATED_SRemoteStreamId";
Henrik Boström5b3541f2018-03-19 12:52:56772 // peer-connection
Henrik Boström8dfc90f2022-09-02 07:39:29773 graph.peer_connection_id = "P";
Henrik Boström646fda02019-05-22 13:49:42774 // media-source (kind: video)
Henrik Boström8dfc90f2022-09-02 07:39:29775 graph.media_source_id = "SV" + rtc::ToString(graph.sender->AttachmentId());
Henrik Boström5b3541f2018-03-19 12:52:56776
777 // Expected stats graph:
778 //
Henrik Boström646fda02019-05-22 13:49:42779 // +--- track (sender) stream (remote stream) ---> track (receiver)
780 // | ^ ^
781 // | | |
782 // | +--------- outbound-rtp inbound-rtp ---------------+
783 // | | | | | |
784 // | | v v v v
785 // | | codec (send) transport codec (recv) peer-connection
786 // v v
787 // media-source
Henrik Boström5b3541f2018-03-19 12:52:56788
789 // Verify the stats graph is set up correctly.
790 graph.full_report = stats_->GetStatsReport();
Henrik Boström646fda02019-05-22 13:49:42791 EXPECT_EQ(graph.full_report->size(), 10u);
Henrik Boström5b3541f2018-03-19 12:52:56792 EXPECT_TRUE(graph.full_report->Get(graph.send_codec_id));
793 EXPECT_TRUE(graph.full_report->Get(graph.recv_codec_id));
794 EXPECT_TRUE(graph.full_report->Get(graph.outbound_rtp_id));
795 EXPECT_TRUE(graph.full_report->Get(graph.inbound_rtp_id));
796 EXPECT_TRUE(graph.full_report->Get(graph.transport_id));
797 EXPECT_TRUE(graph.full_report->Get(graph.sender_track_id));
798 EXPECT_TRUE(graph.full_report->Get(graph.receiver_track_id));
799 EXPECT_TRUE(graph.full_report->Get(graph.remote_stream_id));
800 EXPECT_TRUE(graph.full_report->Get(graph.peer_connection_id));
Henrik Boström646fda02019-05-22 13:49:42801 EXPECT_TRUE(graph.full_report->Get(graph.media_source_id));
Henrik Boström15166b22022-10-19 09:06:58802 const auto& sender_track =
803 graph.full_report->Get(graph.sender_track_id)
804 ->cast_to<DEPRECATED_RTCMediaStreamTrackStats>();
Henrik Boström646fda02019-05-22 13:49:42805 EXPECT_EQ(*sender_track.media_source_id, graph.media_source_id);
Henrik Boström5b3541f2018-03-19 12:52:56806 const auto& outbound_rtp = graph.full_report->Get(graph.outbound_rtp_id)
807 ->cast_to<RTCOutboundRTPStreamStats>();
Henrik Boström646fda02019-05-22 13:49:42808 EXPECT_EQ(*outbound_rtp.media_source_id, graph.media_source_id);
Henrik Boström5b3541f2018-03-19 12:52:56809 EXPECT_EQ(*outbound_rtp.codec_id, graph.send_codec_id);
810 EXPECT_EQ(*outbound_rtp.track_id, graph.sender_track_id);
811 EXPECT_EQ(*outbound_rtp.transport_id, graph.transport_id);
812 const auto& inbound_rtp = graph.full_report->Get(graph.inbound_rtp_id)
813 ->cast_to<RTCInboundRTPStreamStats>();
814 EXPECT_EQ(*inbound_rtp.codec_id, graph.recv_codec_id);
815 EXPECT_EQ(*inbound_rtp.track_id, graph.receiver_track_id);
816 EXPECT_EQ(*inbound_rtp.transport_id, graph.transport_id);
817
818 return graph;
819 }
820
Alessio Bazzicaf7b1b952021-03-23 16:23:04821 // Sets up an example stats graph (see ASCII art below) for an audio only call
822 // and checks that the expected stats are generated.
823 ExampleStatsGraph SetupExampleStatsVoiceGraph(
824 bool add_remote_outbound_stats) {
825 constexpr uint32_t kLocalSsrc = 3;
826 constexpr uint32_t kRemoteSsrc = 4;
827 ExampleStatsGraph graph;
828
829 // codec (send)
Henrik Boström8dfc90f2022-09-02 07:39:29830 graph.send_codec_id = "COTTransportName1_1";
Alessio Bazzicaf7b1b952021-03-23 16:23:04831 cricket::VoiceMediaInfo media_info;
832 RtpCodecParameters send_codec;
833 send_codec.payload_type = 1;
834 send_codec.clock_rate = 0;
835 media_info.send_codecs.insert(
836 std::make_pair(send_codec.payload_type, send_codec));
837 // codec (recv)
Henrik Boström8dfc90f2022-09-02 07:39:29838 graph.recv_codec_id = "CITTransportName1_2";
Alessio Bazzicaf7b1b952021-03-23 16:23:04839 RtpCodecParameters recv_codec;
840 recv_codec.payload_type = 2;
841 recv_codec.clock_rate = 0;
842 media_info.receive_codecs.insert(
843 std::make_pair(recv_codec.payload_type, recv_codec));
844 // outbound-rtp
Henrik Boströmb43e3bb2022-09-26 10:36:44845 graph.outbound_rtp_id = "OTTransportName1A3";
Alessio Bazzicaf7b1b952021-03-23 16:23:04846 media_info.senders.push_back(cricket::VoiceSenderInfo());
847 media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
848 media_info.senders[0].local_stats[0].ssrc = kLocalSsrc;
849 media_info.senders[0].codec_payload_type = send_codec.payload_type;
850 // inbound-rtp
Henrik Boströmb43e3bb2022-09-26 10:36:44851 graph.inbound_rtp_id = "ITTransportName1A4";
Alessio Bazzicaf7b1b952021-03-23 16:23:04852 media_info.receivers.push_back(cricket::VoiceReceiverInfo());
853 media_info.receivers[0].local_stats.push_back(cricket::SsrcReceiverInfo());
854 media_info.receivers[0].local_stats[0].ssrc = kRemoteSsrc;
855 media_info.receivers[0].codec_payload_type = recv_codec.payload_type;
856 // remote-outbound-rtp
857 if (add_remote_outbound_stats) {
Henrik Boström8dfc90f2022-09-02 07:39:29858 graph.remote_outbound_rtp_id = "ROA4";
Alessio Bazzicaf7b1b952021-03-23 16:23:04859 media_info.receivers[0].last_sender_report_timestamp_ms =
860 kRemoteOutboundStatsTimestampMs;
861 media_info.receivers[0].last_sender_report_remote_timestamp_ms =
862 kRemoteOutboundStatsRemoteTimestampMs;
863 media_info.receivers[0].sender_reports_packets_sent =
864 kRemoteOutboundStatsPacketsSent;
865 media_info.receivers[0].sender_reports_bytes_sent =
866 kRemoteOutboundStatsBytesSent;
867 media_info.receivers[0].sender_reports_reports_count =
868 kRemoteOutboundStatsReportsCount;
869 }
870
871 // transport
Henrik Boström8dfc90f2022-09-02 07:39:29872 graph.transport_id = "TTransportName1";
Tommi19015512022-02-02 10:49:35873 pc_->AddVoiceChannel("VoiceMid", "TransportName", media_info);
Alessio Bazzicaf7b1b952021-03-23 16:23:04874 // track (sender)
875 graph.sender = stats_->SetupLocalTrackAndSender(
876 cricket::MEDIA_TYPE_AUDIO, "LocalAudioTrackID", kLocalSsrc, false, 50);
Henrik Boström8dfc90f2022-09-02 07:39:29877 graph.sender_track_id =
878 "DEPRECATED_TO" + rtc::ToString(graph.sender->AttachmentId());
Alessio Bazzicaf7b1b952021-03-23 16:23:04879 // track (receiver) and stream (remote stream)
880 graph.receiver = stats_->SetupRemoteTrackAndReceiver(
881 cricket::MEDIA_TYPE_AUDIO, "RemoteAudioTrackID", "RemoteStreamId",
882 kRemoteSsrc);
Henrik Boström8dfc90f2022-09-02 07:39:29883 graph.receiver_track_id =
884 "DEPRECATED_TI" + rtc::ToString(graph.receiver->AttachmentId());
885 graph.remote_stream_id = "DEPRECATED_SRemoteStreamId";
Alessio Bazzicaf7b1b952021-03-23 16:23:04886 // peer-connection
Henrik Boström8dfc90f2022-09-02 07:39:29887 graph.peer_connection_id = "P";
Alessio Bazzicaf7b1b952021-03-23 16:23:04888 // media-source (kind: video)
Henrik Boström8dfc90f2022-09-02 07:39:29889 graph.media_source_id = "SA" + rtc::ToString(graph.sender->AttachmentId());
Alessio Bazzicaf7b1b952021-03-23 16:23:04890
891 // Expected stats graph:
892 //
893 // +--- track (sender) stream (remote stream) ---> track (receiver)
894 // | ^ ^
895 // | | |
896 // | +--------- outbound-rtp inbound-rtp ---------------+
897 // | | | | | |
898 // | | v v v v
899 // | | codec (send) transport codec (recv) peer-connection
900 // v v
901 // media-source
902
903 // Verify the stats graph is set up correctly.
904 graph.full_report = stats_->GetStatsReport();
905 EXPECT_EQ(graph.full_report->size(), add_remote_outbound_stats ? 11u : 10u);
906 EXPECT_TRUE(graph.full_report->Get(graph.send_codec_id));
907 EXPECT_TRUE(graph.full_report->Get(graph.recv_codec_id));
908 EXPECT_TRUE(graph.full_report->Get(graph.outbound_rtp_id));
909 EXPECT_TRUE(graph.full_report->Get(graph.inbound_rtp_id));
910 EXPECT_TRUE(graph.full_report->Get(graph.transport_id));
911 EXPECT_TRUE(graph.full_report->Get(graph.sender_track_id));
912 EXPECT_TRUE(graph.full_report->Get(graph.receiver_track_id));
913 EXPECT_TRUE(graph.full_report->Get(graph.remote_stream_id));
914 EXPECT_TRUE(graph.full_report->Get(graph.peer_connection_id));
915 EXPECT_TRUE(graph.full_report->Get(graph.media_source_id));
916 // `graph.remote_outbound_rtp_id` is omitted on purpose so that expectations
917 // can be added by the caller depending on what value it sets for the
918 // `add_remote_outbound_stats` argument.
Henrik Boström15166b22022-10-19 09:06:58919 const auto& sender_track =
920 graph.full_report->Get(graph.sender_track_id)
921 ->cast_to<DEPRECATED_RTCMediaStreamTrackStats>();
Alessio Bazzicaf7b1b952021-03-23 16:23:04922 EXPECT_EQ(*sender_track.media_source_id, graph.media_source_id);
923 const auto& outbound_rtp = graph.full_report->Get(graph.outbound_rtp_id)
924 ->cast_to<RTCOutboundRTPStreamStats>();
925 EXPECT_EQ(*outbound_rtp.media_source_id, graph.media_source_id);
926 EXPECT_EQ(*outbound_rtp.codec_id, graph.send_codec_id);
927 EXPECT_EQ(*outbound_rtp.track_id, graph.sender_track_id);
928 EXPECT_EQ(*outbound_rtp.transport_id, graph.transport_id);
929 const auto& inbound_rtp = graph.full_report->Get(graph.inbound_rtp_id)
930 ->cast_to<RTCInboundRTPStreamStats>();
931 EXPECT_EQ(*inbound_rtp.codec_id, graph.recv_codec_id);
932 EXPECT_EQ(*inbound_rtp.track_id, graph.receiver_track_id);
933 EXPECT_EQ(*inbound_rtp.transport_id, graph.transport_id);
934
935 return graph;
936 }
937
hbosc82f2e12016-09-05 08:36:50938 protected:
Steve Anton5b387312018-02-03 00:00:20939 rtc::ScopedFakeClock fake_clock_;
Niels Möller83830f32022-05-20 07:12:57940 rtc::AutoThread main_thread_;
Steve Anton5b387312018-02-03 00:00:20941 rtc::scoped_refptr<FakePeerConnectionForStats> pc_;
942 std::unique_ptr<RTCStatsCollectorWrapper> stats_;
hbosc82f2e12016-09-05 08:36:50943};
944
945TEST_F(RTCStatsCollectorTest, SingleCallback) {
946 rtc::scoped_refptr<const RTCStatsReport> result;
Steve Anton5b387312018-02-03 00:00:20947 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&result));
Niels Möllerafb246b2022-04-20 12:26:50948 EXPECT_TRUE_WAIT(result != nullptr, kGetStatsReportTimeoutMs);
hbosc82f2e12016-09-05 08:36:50949}
950
951TEST_F(RTCStatsCollectorTest, MultipleCallbacks) {
Steve Anton5b387312018-02-03 00:00:20952 rtc::scoped_refptr<const RTCStatsReport> a, b, c;
953 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&a));
954 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&b));
955 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&c));
Niels Möllerafb246b2022-04-20 12:26:50956 EXPECT_TRUE_WAIT(a != nullptr, kGetStatsReportTimeoutMs);
957 EXPECT_TRUE_WAIT(b != nullptr, kGetStatsReportTimeoutMs);
958 EXPECT_TRUE_WAIT(c != nullptr, kGetStatsReportTimeoutMs);
Steve Anton5b387312018-02-03 00:00:20959
hbosc82f2e12016-09-05 08:36:50960 EXPECT_EQ(a.get(), b.get());
961 EXPECT_EQ(b.get(), c.get());
962}
963
964TEST_F(RTCStatsCollectorTest, CachedStatsReports) {
Artem Titov880fa812021-07-30 20:30:23965 // Caching should ensure `a` and `b` are the same report.
Steve Anton5b387312018-02-03 00:00:20966 rtc::scoped_refptr<const RTCStatsReport> a = stats_->GetStatsReport();
967 rtc::scoped_refptr<const RTCStatsReport> b = stats_->GetStatsReport();
hbosd565b732016-08-30 21:04:35968 EXPECT_EQ(a.get(), b.get());
969 // Invalidate cache by clearing it.
Steve Anton5b387312018-02-03 00:00:20970 stats_->stats_collector()->ClearCachedStatsReport();
971 rtc::scoped_refptr<const RTCStatsReport> c = stats_->GetStatsReport();
hbosd565b732016-08-30 21:04:35972 EXPECT_NE(b.get(), c.get());
973 // Invalidate cache by advancing time.
Danil Chapovalov0c626af2020-02-10 10:16:00974 fake_clock_.AdvanceTime(TimeDelta::Millis(51));
Steve Anton5b387312018-02-03 00:00:20975 rtc::scoped_refptr<const RTCStatsReport> d = stats_->GetStatsReport();
hbosd565b732016-08-30 21:04:35976 EXPECT_TRUE(d);
977 EXPECT_NE(c.get(), d.get());
978}
979
hbosc82f2e12016-09-05 08:36:50980TEST_F(RTCStatsCollectorTest, MultipleCallbacksWithInvalidatedCacheInBetween) {
Steve Anton5b387312018-02-03 00:00:20981 rtc::scoped_refptr<const RTCStatsReport> a, b, c;
982 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&a));
983 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&b));
hbosc82f2e12016-09-05 08:36:50984 // Cache is invalidated after 50 ms.
Danil Chapovalov0c626af2020-02-10 10:16:00985 fake_clock_.AdvanceTime(TimeDelta::Millis(51));
Steve Anton5b387312018-02-03 00:00:20986 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&c));
Niels Möllerafb246b2022-04-20 12:26:50987 EXPECT_TRUE_WAIT(a != nullptr, kGetStatsReportTimeoutMs);
988 EXPECT_TRUE_WAIT(b != nullptr, kGetStatsReportTimeoutMs);
989 EXPECT_TRUE_WAIT(c != nullptr, kGetStatsReportTimeoutMs);
hbosc82f2e12016-09-05 08:36:50990 EXPECT_EQ(a.get(), b.get());
Artem Titov880fa812021-07-30 20:30:23991 // The act of doing `AdvanceTime` processes all messages. If this was not the
992 // case we might not require `c` to be fresher than `b`.
hbosc82f2e12016-09-05 08:36:50993 EXPECT_NE(c.get(), b.get());
994}
995
Harald Alvestrand910cdc22020-01-09 11:58:23996TEST_F(RTCStatsCollectorTest, ToJsonProducesParseableJson) {
997 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
998 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
999 std::string json_format = report->ToJson();
Mirko Bonadeie99f6872021-06-24 13:24:591000
1001 Json::CharReaderBuilder builder;
Harald Alvestrand910cdc22020-01-09 11:58:231002 Json::Value json_value;
Mirko Bonadeie99f6872021-06-24 13:24:591003 std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
1004 ASSERT_TRUE(reader->parse(json_format.c_str(),
1005 json_format.c_str() + json_format.size(),
1006 &json_value, nullptr));
1007
Harald Alvestrand910cdc22020-01-09 11:58:231008 // A very brief sanity check on the result.
1009 EXPECT_EQ(report->size(), json_value.size());
1010}
1011
hbos6ab97ce02016-10-03 21:16:561012TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsSingle) {
Steve Anton5b387312018-02-03 00:00:201013 const char kTransportName[] = "transport";
1014
1015 pc_->AddVoiceChannel("audio", kTransportName);
1016
hbos6ab97ce02016-10-03 21:16:561017 std::unique_ptr<CertificateInfo> local_certinfo =
1018 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 13:03:051019 std::vector<std::string>({"(local) single certificate"}));
Steve Anton5b387312018-02-03 00:00:201020 pc_->SetLocalCertificate(kTransportName, local_certinfo->certificate);
1021
hbos6ab97ce02016-10-03 21:16:561022 std::unique_ptr<CertificateInfo> remote_certinfo =
1023 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 13:03:051024 std::vector<std::string>({"(remote) single certificate"}));
Taylor Brandstetterc3928662018-02-23 21:04:511025 pc_->SetRemoteCertChain(
Benjamin Wright6c6c9df2018-10-25 08:16:261026 kTransportName,
1027 remote_certinfo->certificate->GetSSLCertificateChain().Clone());
hbos6ab97ce02016-10-03 21:16:561028
Steve Anton5b387312018-02-03 00:00:201029 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos6ab97ce02016-10-03 21:16:561030
hbos23368e12016-12-21 12:29:171031 ExpectReportContainsCertificateInfo(report, *local_certinfo);
1032 ExpectReportContainsCertificateInfo(report, *remote_certinfo);
hbos6ab97ce02016-10-03 21:16:561033}
1034
Henrik Boströmda6297d2022-09-19 09:33:231035// These SSRC collisions are legal.
1036TEST_F(RTCStatsCollectorTest, ValidSsrcCollisionDoesNotCrash) {
1037 // BUNDLE audio/video inbound/outbound. Unique SSRCs needed within the BUNDLE.
1038 cricket::VoiceMediaInfo mid1_info;
1039 mid1_info.receivers.emplace_back();
1040 mid1_info.receivers[0].add_ssrc(1);
1041 mid1_info.senders.emplace_back();
1042 mid1_info.senders[0].add_ssrc(2);
1043 pc_->AddVoiceChannel("Mid1", "Transport1", mid1_info);
1044 cricket::VideoMediaInfo mid2_info;
1045 mid2_info.receivers.emplace_back();
1046 mid2_info.receivers[0].add_ssrc(3);
1047 mid2_info.senders.emplace_back();
1048 mid2_info.senders[0].add_ssrc(4);
1049 pc_->AddVideoChannel("Mid2", "Transport1", mid2_info);
1050 // Now create a second BUNDLE group with SSRCs colliding with the first group
1051 // (but again no collisions within the group).
1052 cricket::VoiceMediaInfo mid3_info;
1053 mid3_info.receivers.emplace_back();
1054 mid3_info.receivers[0].add_ssrc(1);
1055 mid3_info.senders.emplace_back();
1056 mid3_info.senders[0].add_ssrc(2);
1057 pc_->AddVoiceChannel("Mid3", "Transport2", mid3_info);
1058 cricket::VideoMediaInfo mid4_info;
1059 mid4_info.receivers.emplace_back();
1060 mid4_info.receivers[0].add_ssrc(3);
1061 mid4_info.senders.emplace_back();
1062 mid4_info.senders[0].add_ssrc(4);
1063 pc_->AddVideoChannel("Mid4", "Transport2", mid4_info);
1064
1065 // This should not crash (https://crbug.com/1361612).
1066 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1067 auto inbound_rtps = report->GetStatsOfType<RTCInboundRTPStreamStats>();
1068 auto outbound_rtps = report->GetStatsOfType<RTCOutboundRTPStreamStats>();
Henrik Boströmb43e3bb2022-09-26 10:36:441069 EXPECT_EQ(inbound_rtps.size(), 4u);
1070 EXPECT_EQ(outbound_rtps.size(), 4u);
Henrik Boströmda6297d2022-09-19 09:33:231071}
1072
1073// These SSRC collisions are illegal, so it is not clear if this setup can
1074// happen even when talking to a malicious endpoint, but simulate illegal SSRC
1075// collisions just to make sure we don't crash in even the most extreme cases.
1076TEST_F(RTCStatsCollectorTest, InvalidSsrcCollisionDoesNotCrash) {
1077 // One SSRC to rule them all.
1078 cricket::VoiceMediaInfo mid1_info;
1079 mid1_info.receivers.emplace_back();
1080 mid1_info.receivers[0].add_ssrc(1);
1081 mid1_info.senders.emplace_back();
1082 mid1_info.senders[0].add_ssrc(1);
1083 pc_->AddVoiceChannel("Mid1", "BundledTransport", mid1_info);
1084 cricket::VideoMediaInfo mid2_info;
1085 mid2_info.receivers.emplace_back();
1086 mid2_info.receivers[0].add_ssrc(1);
1087 mid2_info.senders.emplace_back();
1088 mid2_info.senders[0].add_ssrc(1);
1089 pc_->AddVideoChannel("Mid2", "BundledTransport", mid2_info);
1090 cricket::VoiceMediaInfo mid3_info;
1091 mid3_info.receivers.emplace_back();
1092 mid3_info.receivers[0].add_ssrc(1);
1093 mid3_info.senders.emplace_back();
1094 mid3_info.senders[0].add_ssrc(1);
1095 pc_->AddVoiceChannel("Mid3", "BundledTransport", mid3_info);
1096 cricket::VideoMediaInfo mid4_info;
1097 mid4_info.receivers.emplace_back();
1098 mid4_info.receivers[0].add_ssrc(1);
1099 mid4_info.senders.emplace_back();
1100 mid4_info.senders[0].add_ssrc(1);
1101 pc_->AddVideoChannel("Mid4", "BundledTransport", mid4_info);
1102
1103 // This should not crash (https://crbug.com/1361612).
1104 stats_->GetStatsReport();
1105 // Because this setup is illegal, there is no "right answer" to how the report
1106 // should look. We only care about not crashing.
1107}
1108
Henrik Boström31c373b2022-09-26 12:56:211109TEST_F(RTCStatsCollectorTest, CollectRTCCodecStatsOnlyIfReferenced) {
hbos0adb8282016-11-23 10:32:061110 // Audio
1111 cricket::VoiceMediaInfo voice_media_info;
1112
1113 RtpCodecParameters inbound_audio_codec;
1114 inbound_audio_codec.payload_type = 1;
deadbeefe702b302017-02-04 20:09:011115 inbound_audio_codec.kind = cricket::MEDIA_TYPE_AUDIO;
1116 inbound_audio_codec.name = "opus";
Oskar Sundbomcbc71b22017-11-16 09:56:071117 inbound_audio_codec.clock_rate = 1337;
Johannes Kron72d69152020-02-10 13:05:551118 inbound_audio_codec.num_channels = 1;
1119 inbound_audio_codec.parameters = {{"minptime", "10"}, {"useinbandfec", "1"}};
hbos0adb8282016-11-23 10:32:061120 voice_media_info.receive_codecs.insert(
1121 std::make_pair(inbound_audio_codec.payload_type, inbound_audio_codec));
1122
1123 RtpCodecParameters outbound_audio_codec;
1124 outbound_audio_codec.payload_type = 2;
deadbeefe702b302017-02-04 20:09:011125 outbound_audio_codec.kind = cricket::MEDIA_TYPE_AUDIO;
1126 outbound_audio_codec.name = "isac";
Oskar Sundbomcbc71b22017-11-16 09:56:071127 outbound_audio_codec.clock_rate = 1338;
Johannes Kron72d69152020-02-10 13:05:551128 outbound_audio_codec.num_channels = 2;
hbos0adb8282016-11-23 10:32:061129 voice_media_info.send_codecs.insert(
1130 std::make_pair(outbound_audio_codec.payload_type, outbound_audio_codec));
1131
hbos0adb8282016-11-23 10:32:061132 // Video
1133 cricket::VideoMediaInfo video_media_info;
1134
1135 RtpCodecParameters inbound_video_codec;
1136 inbound_video_codec.payload_type = 3;
deadbeefe702b302017-02-04 20:09:011137 inbound_video_codec.kind = cricket::MEDIA_TYPE_VIDEO;
1138 inbound_video_codec.name = "H264";
Oskar Sundbomcbc71b22017-11-16 09:56:071139 inbound_video_codec.clock_rate = 1339;
Johannes Kron72d69152020-02-10 13:05:551140 inbound_video_codec.parameters = {{"level-asymmetry-allowed", "1"},
1141 {"packetization-mode", "1"},
1142 {"profile-level-id", "42001f"}};
hbos0adb8282016-11-23 10:32:061143 video_media_info.receive_codecs.insert(
1144 std::make_pair(inbound_video_codec.payload_type, inbound_video_codec));
1145
1146 RtpCodecParameters outbound_video_codec;
1147 outbound_video_codec.payload_type = 4;
deadbeefe702b302017-02-04 20:09:011148 outbound_video_codec.kind = cricket::MEDIA_TYPE_VIDEO;
1149 outbound_video_codec.name = "VP8";
Oskar Sundbomcbc71b22017-11-16 09:56:071150 outbound_video_codec.clock_rate = 1340;
hbos0adb8282016-11-23 10:32:061151 video_media_info.send_codecs.insert(
1152 std::make_pair(outbound_video_codec.payload_type, outbound_video_codec));
1153
Henrik Boström31c373b2022-09-26 12:56:211154 // Ensure the above codecs are referenced.
1155 cricket::VoiceReceiverInfo inbound_audio_info;
1156 inbound_audio_info.add_ssrc(10);
1157 inbound_audio_info.codec_payload_type = 1;
1158 voice_media_info.receivers.push_back(inbound_audio_info);
1159
1160 cricket::VoiceSenderInfo outbound_audio_info;
1161 outbound_audio_info.add_ssrc(20);
1162 outbound_audio_info.codec_payload_type = 2;
1163 voice_media_info.senders.push_back(outbound_audio_info);
1164
1165 cricket::VideoReceiverInfo inbound_video_info;
1166 inbound_video_info.add_ssrc(30);
1167 inbound_video_info.codec_payload_type = 3;
1168 video_media_info.receivers.push_back(inbound_video_info);
1169
1170 cricket::VideoSenderInfo outbound_video_info;
1171 outbound_video_info.add_ssrc(40);
1172 outbound_video_info.codec_payload_type = 4;
1173 video_media_info.senders.push_back(outbound_video_info);
1174
1175 FakeVoiceMediaChannelForStats* audio_channel =
1176 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
1177 FakeVideoMediaChannelForStats* video_channel =
1178 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
hbos0adb8282016-11-23 10:32:061179
Steve Anton5b387312018-02-03 00:00:201180 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos0adb8282016-11-23 10:32:061181
Henrik Boströmb2be3922022-09-02 07:37:081182 RTCCodecStats expected_inbound_audio_codec(
Henrik Boström8dfc90f2022-09-02 07:39:291183 "CITTransportName1_1_minptime=10;useinbandfec=1", report->timestamp_us());
hbos0adb8282016-11-23 10:32:061184 expected_inbound_audio_codec.payload_type = 1;
hbos13f54b22017-02-28 14:56:041185 expected_inbound_audio_codec.mime_type = "audio/opus";
hbos0adb8282016-11-23 10:32:061186 expected_inbound_audio_codec.clock_rate = 1337;
Johannes Kron72d69152020-02-10 13:05:551187 expected_inbound_audio_codec.channels = 1;
1188 expected_inbound_audio_codec.sdp_fmtp_line = "minptime=10;useinbandfec=1";
Henrik Boström8dfc90f2022-09-02 07:39:291189 expected_inbound_audio_codec.transport_id = "TTransportName1";
hbos0adb8282016-11-23 10:32:061190
Henrik Boström8dfc90f2022-09-02 07:39:291191 RTCCodecStats expected_outbound_audio_codec("COTTransportName1_2",
1192 report->timestamp_us());
hbos0adb8282016-11-23 10:32:061193 expected_outbound_audio_codec.payload_type = 2;
hbos13f54b22017-02-28 14:56:041194 expected_outbound_audio_codec.mime_type = "audio/isac";
hbos0adb8282016-11-23 10:32:061195 expected_outbound_audio_codec.clock_rate = 1338;
Johannes Kron72d69152020-02-10 13:05:551196 expected_outbound_audio_codec.channels = 2;
Henrik Boström8dfc90f2022-09-02 07:39:291197 expected_outbound_audio_codec.transport_id = "TTransportName1";
hbos0adb8282016-11-23 10:32:061198
Henrik Boströmb2be3922022-09-02 07:37:081199 RTCCodecStats expected_inbound_video_codec(
Henrik Boström8dfc90f2022-09-02 07:39:291200 "CITTransportName1_3_level-asymmetry-allowed=1;"
Henrik Boströmb2be3922022-09-02 07:37:081201 "packetization-mode=1;profile-level-id=42001f",
1202 report->timestamp_us());
hbos0adb8282016-11-23 10:32:061203 expected_inbound_video_codec.payload_type = 3;
hbos13f54b22017-02-28 14:56:041204 expected_inbound_video_codec.mime_type = "video/H264";
hbos0adb8282016-11-23 10:32:061205 expected_inbound_video_codec.clock_rate = 1339;
Johannes Kron72d69152020-02-10 13:05:551206 expected_inbound_video_codec.sdp_fmtp_line =
1207 "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f";
Henrik Boström8dfc90f2022-09-02 07:39:291208 expected_inbound_video_codec.transport_id = "TTransportName1";
hbos0adb8282016-11-23 10:32:061209
Henrik Boström8dfc90f2022-09-02 07:39:291210 RTCCodecStats expected_outbound_video_codec("COTTransportName1_4",
1211 report->timestamp_us());
hbos0adb8282016-11-23 10:32:061212 expected_outbound_video_codec.payload_type = 4;
hbos13f54b22017-02-28 14:56:041213 expected_outbound_video_codec.mime_type = "video/VP8";
hbos0adb8282016-11-23 10:32:061214 expected_outbound_video_codec.clock_rate = 1340;
Henrik Boström8dfc90f2022-09-02 07:39:291215 expected_outbound_video_codec.transport_id = "TTransportName1";
hbos0adb8282016-11-23 10:32:061216
nissec8ee8822017-01-18 15:20:551217 ASSERT_TRUE(report->Get(expected_inbound_audio_codec.id()));
Yves Gerey665174f2018-06-19 13:03:051218 EXPECT_EQ(
1219 expected_inbound_audio_codec,
1220 report->Get(expected_inbound_audio_codec.id())->cast_to<RTCCodecStats>());
hbos0adb8282016-11-23 10:32:061221
nissec8ee8822017-01-18 15:20:551222 ASSERT_TRUE(report->Get(expected_outbound_audio_codec.id()));
hbos0adb8282016-11-23 10:32:061223 EXPECT_EQ(expected_outbound_audio_codec,
Yves Gerey665174f2018-06-19 13:03:051224 report->Get(expected_outbound_audio_codec.id())
1225 ->cast_to<RTCCodecStats>());
hbos0adb8282016-11-23 10:32:061226
nissec8ee8822017-01-18 15:20:551227 ASSERT_TRUE(report->Get(expected_inbound_video_codec.id()));
Yves Gerey665174f2018-06-19 13:03:051228 EXPECT_EQ(
1229 expected_inbound_video_codec,
1230 report->Get(expected_inbound_video_codec.id())->cast_to<RTCCodecStats>());
hbos0adb8282016-11-23 10:32:061231
nissec8ee8822017-01-18 15:20:551232 ASSERT_TRUE(report->Get(expected_outbound_video_codec.id()));
hbos0adb8282016-11-23 10:32:061233 EXPECT_EQ(expected_outbound_video_codec,
Yves Gerey665174f2018-06-19 13:03:051234 report->Get(expected_outbound_video_codec.id())
1235 ->cast_to<RTCCodecStats>());
Henrik Boström31c373b2022-09-26 12:56:211236
1237 // Now remove all the RTP streams such that there are no live codecId
1238 // references to the codecs, this should result in none of the RTCCodecStats
1239 // being exposed, despite `send_codecs` and `receive_codecs` still being set.
1240 voice_media_info.senders.clear();
1241 voice_media_info.receivers.clear();
1242 audio_channel->SetStats(voice_media_info);
1243 video_media_info.senders.clear();
1244 video_media_info.receivers.clear();
1245 video_channel->SetStats(video_media_info);
1246 stats_->stats_collector()->ClearCachedStatsReport();
1247 report = stats_->GetStatsReport();
1248 EXPECT_FALSE(report->Get(expected_inbound_audio_codec.id()));
1249 EXPECT_FALSE(report->Get(expected_outbound_audio_codec.id()));
1250 EXPECT_FALSE(report->Get(expected_inbound_video_codec.id()));
1251 EXPECT_FALSE(report->Get(expected_outbound_video_codec.id()));
hbos0adb8282016-11-23 10:32:061252}
1253
Henrik Boströmb2be3922022-09-02 07:37:081254TEST_F(RTCStatsCollectorTest, CodecStatsAreCollectedPerTransport) {
1255 // PT=10
1256 RtpCodecParameters outbound_codec_pt10;
1257 outbound_codec_pt10.payload_type = 10;
1258 outbound_codec_pt10.kind = cricket::MEDIA_TYPE_VIDEO;
1259 outbound_codec_pt10.name = "VP8";
1260 outbound_codec_pt10.clock_rate = 9000;
1261
1262 // PT=11
1263 RtpCodecParameters outbound_codec_pt11;
1264 outbound_codec_pt11.payload_type = 11;
1265 outbound_codec_pt11.kind = cricket::MEDIA_TYPE_VIDEO;
1266 outbound_codec_pt11.name = "VP8";
1267 outbound_codec_pt11.clock_rate = 9000;
1268
Henrik Boström31c373b2022-09-26 12:56:211269 // Insert codecs into `send_codecs` and ensure the PTs are referenced by RTP
1270 // streams.
Henrik Boströmb2be3922022-09-02 07:37:081271 cricket::VideoMediaInfo info_pt10;
1272 info_pt10.send_codecs.insert(
1273 std::make_pair(outbound_codec_pt10.payload_type, outbound_codec_pt10));
Henrik Boström31c373b2022-09-26 12:56:211274 info_pt10.senders.emplace_back();
1275 info_pt10.senders[0].add_ssrc(42);
1276 info_pt10.senders[0].codec_payload_type = outbound_codec_pt10.payload_type;
1277
Henrik Boströmb2be3922022-09-02 07:37:081278 cricket::VideoMediaInfo info_pt11;
1279 info_pt11.send_codecs.insert(
1280 std::make_pair(outbound_codec_pt11.payload_type, outbound_codec_pt11));
Henrik Boström31c373b2022-09-26 12:56:211281 info_pt11.senders.emplace_back();
1282 info_pt11.senders[0].add_ssrc(43);
1283 info_pt11.senders[0].codec_payload_type = outbound_codec_pt11.payload_type;
1284
Henrik Boströmb2be3922022-09-02 07:37:081285 cricket::VideoMediaInfo info_pt10_pt11;
1286 info_pt10_pt11.send_codecs.insert(
1287 std::make_pair(outbound_codec_pt10.payload_type, outbound_codec_pt10));
1288 info_pt10_pt11.send_codecs.insert(
1289 std::make_pair(outbound_codec_pt11.payload_type, outbound_codec_pt11));
Henrik Boström31c373b2022-09-26 12:56:211290 info_pt10_pt11.senders.emplace_back();
1291 info_pt10_pt11.senders[0].add_ssrc(44);
1292 info_pt10_pt11.senders[0].codec_payload_type =
1293 outbound_codec_pt10.payload_type;
1294 info_pt10_pt11.senders.emplace_back();
1295 info_pt10_pt11.senders[1].add_ssrc(45);
1296 info_pt10_pt11.senders[1].codec_payload_type =
1297 outbound_codec_pt11.payload_type;
Henrik Boströmb2be3922022-09-02 07:37:081298
1299 // First two mids contain subsets, the third one contains all PTs.
1300 pc_->AddVideoChannel("Mid1", "FirstTransport", info_pt10);
1301 pc_->AddVideoChannel("Mid2", "FirstTransport", info_pt11);
1302 pc_->AddVideoChannel("Mid3", "FirstTransport", info_pt10_pt11);
1303
1304 // There should be no duplicate codecs because all codec references are on the
1305 // same transport.
1306 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1307 auto codec_stats = report->GetStatsOfType<RTCCodecStats>();
1308 EXPECT_EQ(codec_stats.size(), 2u);
1309
1310 // If a second transport is added with the same PT information, this does
1311 // count as different codec objects.
1312 pc_->AddVideoChannel("Mid4", "SecondTransport", info_pt10_pt11);
1313 stats_->stats_collector()->ClearCachedStatsReport();
1314 report = stats_->GetStatsReport();
1315 codec_stats = report->GetStatsOfType<RTCCodecStats>();
1316 EXPECT_EQ(codec_stats.size(), 4u);
1317}
1318
1319TEST_F(RTCStatsCollectorTest, SamePayloadTypeButDifferentFmtpLines) {
1320 // PT=111, useinbandfec=0
1321 RtpCodecParameters inbound_codec_pt111_nofec;
1322 inbound_codec_pt111_nofec.payload_type = 111;
1323 inbound_codec_pt111_nofec.kind = cricket::MEDIA_TYPE_AUDIO;
1324 inbound_codec_pt111_nofec.name = "opus";
1325 inbound_codec_pt111_nofec.clock_rate = 48000;
1326 inbound_codec_pt111_nofec.parameters.insert(
1327 std::make_pair("useinbandfec", "0"));
1328
1329 // PT=111, useinbandfec=1
1330 RtpCodecParameters inbound_codec_pt111_fec;
1331 inbound_codec_pt111_fec.payload_type = 111;
1332 inbound_codec_pt111_fec.kind = cricket::MEDIA_TYPE_AUDIO;
1333 inbound_codec_pt111_fec.name = "opus";
1334 inbound_codec_pt111_fec.clock_rate = 48000;
1335 inbound_codec_pt111_fec.parameters.insert(
1336 std::make_pair("useinbandfec", "1"));
1337
1338 cricket::VideoMediaInfo info_nofec;
Henrik Boström31c373b2022-09-26 12:56:211339 info_nofec.receive_codecs.insert(std::make_pair(
Henrik Boströmb2be3922022-09-02 07:37:081340 inbound_codec_pt111_nofec.payload_type, inbound_codec_pt111_nofec));
Henrik Boström31c373b2022-09-26 12:56:211341 info_nofec.receivers.emplace_back();
1342 info_nofec.receivers[0].add_ssrc(123);
1343 info_nofec.receivers[0].codec_payload_type =
1344 inbound_codec_pt111_nofec.payload_type;
Henrik Boströmb2be3922022-09-02 07:37:081345 cricket::VideoMediaInfo info_fec;
Henrik Boström31c373b2022-09-26 12:56:211346 info_fec.receive_codecs.insert(std::make_pair(
Henrik Boströmb2be3922022-09-02 07:37:081347 inbound_codec_pt111_fec.payload_type, inbound_codec_pt111_fec));
Henrik Boström31c373b2022-09-26 12:56:211348 info_fec.receivers.emplace_back();
1349 info_fec.receivers[0].add_ssrc(321);
1350 info_fec.receivers[0].codec_payload_type =
1351 inbound_codec_pt111_fec.payload_type;
Henrik Boströmb2be3922022-09-02 07:37:081352
1353 // First two mids contain subsets, the third one contains all PTs.
1354 pc_->AddVideoChannel("Mid1", "BundledTransport", info_nofec);
1355 pc_->AddVideoChannel("Mid2", "BundledTransport", info_fec);
1356
1357 // Despite having the same PT we should see two codec stats because their FMTP
1358 // lines are different.
1359 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1360 auto codec_stats = report->GetStatsOfType<RTCCodecStats>();
1361 EXPECT_EQ(codec_stats.size(), 2u);
1362
Henrik Boström31c373b2022-09-26 12:56:211363 // Ensure SSRC uniqueness before the next AddVideoChannel() call. SSRCs need
1364 // to be unique on different m= sections when using BUNDLE.
1365 info_nofec.receivers[0].local_stats[0].ssrc = 12;
1366 info_fec.receivers[0].local_stats[0].ssrc = 21;
Henrik Boströmb2be3922022-09-02 07:37:081367 // Adding more m= sections that does have the same FMTP lines does not result
1368 // in duplicates.
1369 pc_->AddVideoChannel("Mid3", "BundledTransport", info_nofec);
1370 pc_->AddVideoChannel("Mid4", "BundledTransport", info_fec);
1371 stats_->stats_collector()->ClearCachedStatsReport();
1372 report = stats_->GetStatsReport();
1373 codec_stats = report->GetStatsOfType<RTCCodecStats>();
1374 EXPECT_EQ(codec_stats.size(), 2u);
1375
1376 // Same FMTP line but a different PT does count as a new codec.
1377 // PT=112, useinbandfec=1
1378 RtpCodecParameters inbound_codec_pt112_fec;
1379 inbound_codec_pt112_fec.payload_type = 112;
1380 inbound_codec_pt112_fec.kind = cricket::MEDIA_TYPE_AUDIO;
1381 inbound_codec_pt112_fec.name = "opus";
1382 inbound_codec_pt112_fec.clock_rate = 48000;
1383 inbound_codec_pt112_fec.parameters.insert(
1384 std::make_pair("useinbandfec", "1"));
1385 cricket::VideoMediaInfo info_fec_pt112;
Henrik Boström31c373b2022-09-26 12:56:211386 info_fec_pt112.receive_codecs.insert(std::make_pair(
Henrik Boströmb2be3922022-09-02 07:37:081387 inbound_codec_pt112_fec.payload_type, inbound_codec_pt112_fec));
Henrik Boström31c373b2022-09-26 12:56:211388 info_fec_pt112.receivers.emplace_back();
1389 info_fec_pt112.receivers[0].add_ssrc(112);
1390 info_fec_pt112.receivers[0].codec_payload_type =
1391 inbound_codec_pt112_fec.payload_type;
Henrik Boströmb2be3922022-09-02 07:37:081392 pc_->AddVideoChannel("Mid5", "BundledTransport", info_fec_pt112);
1393 stats_->stats_collector()->ClearCachedStatsReport();
1394 report = stats_->GetStatsReport();
1395 codec_stats = report->GetStatsOfType<RTCCodecStats>();
1396 EXPECT_EQ(codec_stats.size(), 3u);
1397}
1398
hbos6ab97ce02016-10-03 21:16:561399TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsMultiple) {
Steve Anton5b387312018-02-03 00:00:201400 const char kAudioTransport[] = "audio";
1401 const char kVideoTransport[] = "video";
1402
1403 pc_->AddVoiceChannel("audio", kAudioTransport);
Tommi19015512022-02-02 10:49:351404
hbos6ab97ce02016-10-03 21:16:561405 std::unique_ptr<CertificateInfo> audio_local_certinfo =
1406 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 13:03:051407 std::vector<std::string>({"(local) audio"}));
Steve Anton5b387312018-02-03 00:00:201408 pc_->SetLocalCertificate(kAudioTransport, audio_local_certinfo->certificate);
hbos6ab97ce02016-10-03 21:16:561409 std::unique_ptr<CertificateInfo> audio_remote_certinfo =
1410 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 13:03:051411 std::vector<std::string>({"(remote) audio"}));
Taylor Brandstetterc3928662018-02-23 21:04:511412 pc_->SetRemoteCertChain(
1413 kAudioTransport,
Benjamin Wright6c6c9df2018-10-25 08:16:261414 audio_remote_certinfo->certificate->GetSSLCertificateChain().Clone());
hbos6ab97ce02016-10-03 21:16:561415
Steve Anton5b387312018-02-03 00:00:201416 pc_->AddVideoChannel("video", kVideoTransport);
hbos6ab97ce02016-10-03 21:16:561417 std::unique_ptr<CertificateInfo> video_local_certinfo =
1418 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 13:03:051419 std::vector<std::string>({"(local) video"}));
Steve Anton5b387312018-02-03 00:00:201420 pc_->SetLocalCertificate(kVideoTransport, video_local_certinfo->certificate);
hbos6ab97ce02016-10-03 21:16:561421 std::unique_ptr<CertificateInfo> video_remote_certinfo =
1422 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 13:03:051423 std::vector<std::string>({"(remote) video"}));
Taylor Brandstetterc3928662018-02-23 21:04:511424 pc_->SetRemoteCertChain(
1425 kVideoTransport,
Benjamin Wright6c6c9df2018-10-25 08:16:261426 video_remote_certinfo->certificate->GetSSLCertificateChain().Clone());
hbos6ab97ce02016-10-03 21:16:561427
Steve Anton5b387312018-02-03 00:00:201428 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos23368e12016-12-21 12:29:171429 ExpectReportContainsCertificateInfo(report, *audio_local_certinfo);
1430 ExpectReportContainsCertificateInfo(report, *audio_remote_certinfo);
1431 ExpectReportContainsCertificateInfo(report, *video_local_certinfo);
1432 ExpectReportContainsCertificateInfo(report, *video_remote_certinfo);
hbos6ab97ce02016-10-03 21:16:561433}
1434
1435TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsChain) {
Steve Anton5b387312018-02-03 00:00:201436 const char kTransportName[] = "transport";
1437
1438 pc_->AddVoiceChannel("audio", kTransportName);
1439
hbos6ab97ce02016-10-03 21:16:561440 std::unique_ptr<CertificateInfo> local_certinfo =
Steve Anton5b387312018-02-03 00:00:201441 CreateFakeCertificateAndInfoFromDers(
1442 {"(local) this", "(local) is", "(local) a", "(local) chain"});
1443 pc_->SetLocalCertificate(kTransportName, local_certinfo->certificate);
1444
hbos6ab97ce02016-10-03 21:16:561445 std::unique_ptr<CertificateInfo> remote_certinfo =
Steve Anton5b387312018-02-03 00:00:201446 CreateFakeCertificateAndInfoFromDers({"(remote) this", "(remote) is",
1447 "(remote) another",
1448 "(remote) chain"});
Taylor Brandstetterc3928662018-02-23 21:04:511449 pc_->SetRemoteCertChain(
Benjamin Wright6c6c9df2018-10-25 08:16:261450 kTransportName,
1451 remote_certinfo->certificate->GetSSLCertificateChain().Clone());
hbos6ab97ce02016-10-03 21:16:561452
Steve Anton5b387312018-02-03 00:00:201453 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos23368e12016-12-21 12:29:171454 ExpectReportContainsCertificateInfo(report, *local_certinfo);
1455 ExpectReportContainsCertificateInfo(report, *remote_certinfo);
hbos6ab97ce02016-10-03 21:16:561456}
1457
Henrik Boström69d23c92022-09-26 12:13:171458TEST_F(RTCStatsCollectorTest, CertificateStatsCache) {
1459 const char kTransportName[] = "transport";
1460 rtc::ScopedFakeClock fake_clock;
1461
1462 pc_->AddVoiceChannel("audio", kTransportName);
1463
1464 // Set local and remote cerificates.
1465 std::unique_ptr<CertificateInfo> initial_local_certinfo =
1466 CreateFakeCertificateAndInfoFromDers({"LocalCertA", "LocalCertB"});
1467 pc_->SetLocalCertificate(kTransportName, initial_local_certinfo->certificate);
1468 std::unique_ptr<CertificateInfo> initial_remote_certinfo =
1469 CreateFakeCertificateAndInfoFromDers({"RemoteCertA", "RemoteCertB"});
1470 pc_->SetRemoteCertChain(
1471 kTransportName,
1472 initial_remote_certinfo->certificate->GetSSLCertificateChain().Clone());
1473 ASSERT_EQ(initial_local_certinfo->fingerprints.size(), 2u);
1474 ASSERT_EQ(initial_remote_certinfo->fingerprints.size(), 2u);
1475
1476 rtc::scoped_refptr<const RTCStatsReport> first_report =
1477 stats_->GetStatsReport();
1478 const auto* first_local_cert0 = GetCertificateStatsFromFingerprint(
1479 first_report, initial_local_certinfo->fingerprints[0]);
1480 const auto* first_local_cert1 = GetCertificateStatsFromFingerprint(
1481 first_report, initial_local_certinfo->fingerprints[1]);
1482 const auto* first_remote_cert0 = GetCertificateStatsFromFingerprint(
1483 first_report, initial_remote_certinfo->fingerprints[0]);
1484 const auto* first_remote_cert1 = GetCertificateStatsFromFingerprint(
1485 first_report, initial_remote_certinfo->fingerprints[1]);
1486 ASSERT_TRUE(first_local_cert0);
1487 ASSERT_TRUE(first_local_cert1);
1488 ASSERT_TRUE(first_remote_cert0);
1489 ASSERT_TRUE(first_remote_cert1);
1490 EXPECT_EQ(first_local_cert0->timestamp_us(), rtc::TimeMicros());
1491 EXPECT_EQ(first_local_cert1->timestamp_us(), rtc::TimeMicros());
1492 EXPECT_EQ(first_remote_cert0->timestamp_us(), rtc::TimeMicros());
1493 EXPECT_EQ(first_remote_cert1->timestamp_us(), rtc::TimeMicros());
1494
1495 // Replace all certificates.
1496 std::unique_ptr<CertificateInfo> updated_local_certinfo =
1497 CreateFakeCertificateAndInfoFromDers(
1498 {"UpdatedLocalCertA", "UpdatedLocalCertB"});
1499 pc_->SetLocalCertificate(kTransportName, updated_local_certinfo->certificate);
1500 std::unique_ptr<CertificateInfo> updated_remote_certinfo =
1501 CreateFakeCertificateAndInfoFromDers(
1502 {"UpdatedRemoteCertA", "UpdatedRemoteCertB"});
1503 pc_->SetRemoteCertChain(
1504 kTransportName,
1505 updated_remote_certinfo->certificate->GetSSLCertificateChain().Clone());
1506 // This test assumes fingerprints are different for the old and new
1507 // certificates.
1508 EXPECT_NE(initial_local_certinfo->fingerprints,
1509 updated_local_certinfo->fingerprints);
1510 EXPECT_NE(initial_remote_certinfo->fingerprints,
1511 updated_remote_certinfo->fingerprints);
1512
1513 // Advance time to ensure a fresh stats report, but don't clear the
1514 // certificate stats cache.
1515 fake_clock.AdvanceTime(TimeDelta::Seconds(1));
1516 rtc::scoped_refptr<const RTCStatsReport> second_report =
1517 stats_->GetStatsReport();
1518 // We expect to see the same certificates as before due to not clearing the
1519 // certificate cache.
1520 const auto* second_local_cert0 =
1521 second_report->GetAs<RTCCertificateStats>(first_local_cert0->id());
1522 const auto* second_local_cert1 =
1523 second_report->GetAs<RTCCertificateStats>(first_local_cert1->id());
1524 const auto* second_remote_cert0 =
1525 second_report->GetAs<RTCCertificateStats>(first_remote_cert0->id());
1526 const auto* second_remote_cert1 =
1527 second_report->GetAs<RTCCertificateStats>(first_remote_cert1->id());
1528 ASSERT_TRUE(second_local_cert0);
1529 ASSERT_TRUE(second_local_cert1);
1530 ASSERT_TRUE(second_remote_cert0);
1531 ASSERT_TRUE(second_remote_cert1);
1532 // The information in the certificate stats are obsolete.
1533 EXPECT_EQ(*second_local_cert0->fingerprint,
1534 initial_local_certinfo->fingerprints[0]);
1535 EXPECT_EQ(*second_local_cert1->fingerprint,
1536 initial_local_certinfo->fingerprints[1]);
1537 EXPECT_EQ(*second_remote_cert0->fingerprint,
1538 initial_remote_certinfo->fingerprints[0]);
1539 EXPECT_EQ(*second_remote_cert1->fingerprint,
1540 initial_remote_certinfo->fingerprints[1]);
1541 // But timestamps are up-to-date, because this is a fresh stats report.
1542 EXPECT_EQ(second_local_cert0->timestamp_us(), rtc::TimeMicros());
1543 EXPECT_EQ(second_local_cert1->timestamp_us(), rtc::TimeMicros());
1544 EXPECT_EQ(second_remote_cert0->timestamp_us(), rtc::TimeMicros());
1545 EXPECT_EQ(second_remote_cert1->timestamp_us(), rtc::TimeMicros());
1546 // The updated certificates are not part of the report yet.
1547 EXPECT_FALSE(GetCertificateStatsFromFingerprint(
1548 second_report, updated_local_certinfo->fingerprints[0]));
1549 EXPECT_FALSE(GetCertificateStatsFromFingerprint(
1550 second_report, updated_local_certinfo->fingerprints[1]));
1551 EXPECT_FALSE(GetCertificateStatsFromFingerprint(
1552 second_report, updated_remote_certinfo->fingerprints[0]));
1553 EXPECT_FALSE(GetCertificateStatsFromFingerprint(
1554 second_report, updated_remote_certinfo->fingerprints[1]));
1555
1556 // Clear the cache, including the cached certificates.
1557 stats_->stats_collector()->ClearCachedStatsReport();
1558 rtc::scoped_refptr<const RTCStatsReport> third_report =
1559 stats_->GetStatsReport();
1560 // Now the old certificates stats should be deleted.
1561 EXPECT_FALSE(third_report->Get(first_local_cert0->id()));
1562 EXPECT_FALSE(third_report->Get(first_local_cert1->id()));
1563 EXPECT_FALSE(third_report->Get(first_remote_cert0->id()));
1564 EXPECT_FALSE(third_report->Get(first_remote_cert1->id()));
1565 // And updated certificates exist.
1566 EXPECT_TRUE(GetCertificateStatsFromFingerprint(
1567 third_report, updated_local_certinfo->fingerprints[0]));
1568 EXPECT_TRUE(GetCertificateStatsFromFingerprint(
1569 third_report, updated_local_certinfo->fingerprints[1]));
1570 EXPECT_TRUE(GetCertificateStatsFromFingerprint(
1571 third_report, updated_remote_certinfo->fingerprints[0]));
1572 EXPECT_TRUE(GetCertificateStatsFromFingerprint(
1573 third_report, updated_remote_certinfo->fingerprints[1]));
1574}
1575
Harald Alvestrand928e7a32019-07-31 11:16:451576TEST_F(RTCStatsCollectorTest, CollectTwoRTCDataChannelStatsWithPendingId) {
Niels Möllere7cc8832022-01-04 14:20:031577 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
1578 /*id=*/-1, DataChannelInterface::kConnecting));
1579 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
1580 /*id=*/-1, DataChannelInterface::kConnecting));
Harald Alvestrand928e7a32019-07-31 11:16:451581
1582 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1583}
1584
hboscc555c52016-10-18 19:48:311585TEST_F(RTCStatsCollectorTest, CollectRTCDataChannelStats) {
Harald Alvestrand928e7a32019-07-31 11:16:451586 // Note: The test assumes data channel IDs are predictable.
1587 // This is not a safe assumption, but in order to make it work for
1588 // the test, we reset the ID allocator at test start.
Taylor Brandstetter3a034e12020-07-09 22:32:341589 SctpDataChannel::ResetInternalIdAllocatorForTesting(-1);
Niels Möllere7cc8832022-01-04 14:20:031590 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
Taylor Brandstetter3a034e12020-07-09 22:32:341591 0, "MockSctpDataChannel0", DataChannelInterface::kConnecting, "udp", 1, 2,
1592 3, 4));
Henrik Boström8dfc90f2022-09-02 07:39:291593 RTCDataChannelStats expected_data_channel0("D0", 0);
Taylor Brandstetter3a034e12020-07-09 22:32:341594 expected_data_channel0.label = "MockSctpDataChannel0";
hbosdbb64d82016-12-21 09:57:461595 expected_data_channel0.protocol = "udp";
Harald Alvestrand10ef8472020-06-05 13:38:511596 expected_data_channel0.data_channel_identifier = 0;
hbosdbb64d82016-12-21 09:57:461597 expected_data_channel0.state = "connecting";
1598 expected_data_channel0.messages_sent = 1;
1599 expected_data_channel0.bytes_sent = 2;
1600 expected_data_channel0.messages_received = 3;
1601 expected_data_channel0.bytes_received = 4;
1602
Niels Möllere7cc8832022-01-04 14:20:031603 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
1604 1, "MockSctpDataChannel1", DataChannelInterface::kOpen, "tcp", 5, 6, 7,
1605 8));
Henrik Boström8dfc90f2022-09-02 07:39:291606 RTCDataChannelStats expected_data_channel1("D1", 0);
Taylor Brandstetter3a034e12020-07-09 22:32:341607 expected_data_channel1.label = "MockSctpDataChannel1";
hbosdbb64d82016-12-21 09:57:461608 expected_data_channel1.protocol = "tcp";
Harald Alvestrand10ef8472020-06-05 13:38:511609 expected_data_channel1.data_channel_identifier = 1;
hbosdbb64d82016-12-21 09:57:461610 expected_data_channel1.state = "open";
1611 expected_data_channel1.messages_sent = 5;
1612 expected_data_channel1.bytes_sent = 6;
1613 expected_data_channel1.messages_received = 7;
1614 expected_data_channel1.bytes_received = 8;
1615
Niels Möllere7cc8832022-01-04 14:20:031616 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
Taylor Brandstetter3a034e12020-07-09 22:32:341617 2, "MockSctpDataChannel2", DataChannelInterface::kClosing, "udp", 9, 10,
1618 11, 12));
Henrik Boström8dfc90f2022-09-02 07:39:291619 RTCDataChannelStats expected_data_channel2("D2", 0);
Taylor Brandstetter3a034e12020-07-09 22:32:341620 expected_data_channel2.label = "MockSctpDataChannel2";
hbosdbb64d82016-12-21 09:57:461621 expected_data_channel2.protocol = "udp";
Harald Alvestrand10ef8472020-06-05 13:38:511622 expected_data_channel2.data_channel_identifier = 2;
hbosdbb64d82016-12-21 09:57:461623 expected_data_channel2.state = "closing";
1624 expected_data_channel2.messages_sent = 9;
1625 expected_data_channel2.bytes_sent = 10;
1626 expected_data_channel2.messages_received = 11;
1627 expected_data_channel2.bytes_received = 12;
1628
Niels Möllere7cc8832022-01-04 14:20:031629 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
1630 3, "MockSctpDataChannel3", DataChannelInterface::kClosed, "tcp", 13, 14,
1631 15, 16));
Henrik Boström8dfc90f2022-09-02 07:39:291632 RTCDataChannelStats expected_data_channel3("D3", 0);
Taylor Brandstetter3a034e12020-07-09 22:32:341633 expected_data_channel3.label = "MockSctpDataChannel3";
hbosdbb64d82016-12-21 09:57:461634 expected_data_channel3.protocol = "tcp";
Harald Alvestrand10ef8472020-06-05 13:38:511635 expected_data_channel3.data_channel_identifier = 3;
hbosdbb64d82016-12-21 09:57:461636 expected_data_channel3.state = "closed";
1637 expected_data_channel3.messages_sent = 13;
1638 expected_data_channel3.bytes_sent = 14;
1639 expected_data_channel3.messages_received = 15;
1640 expected_data_channel3.bytes_received = 16;
hboscc555c52016-10-18 19:48:311641
Steve Anton5b387312018-02-03 00:00:201642 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1643
hbosdbb64d82016-12-21 09:57:461644 ASSERT_TRUE(report->Get(expected_data_channel0.id()));
Yves Gerey665174f2018-06-19 13:03:051645 EXPECT_EQ(
1646 expected_data_channel0,
1647 report->Get(expected_data_channel0.id())->cast_to<RTCDataChannelStats>());
hbosdbb64d82016-12-21 09:57:461648 ASSERT_TRUE(report->Get(expected_data_channel1.id()));
Yves Gerey665174f2018-06-19 13:03:051649 EXPECT_EQ(
1650 expected_data_channel1,
1651 report->Get(expected_data_channel1.id())->cast_to<RTCDataChannelStats>());
hbosdbb64d82016-12-21 09:57:461652 ASSERT_TRUE(report->Get(expected_data_channel2.id()));
Yves Gerey665174f2018-06-19 13:03:051653 EXPECT_EQ(
1654 expected_data_channel2,
1655 report->Get(expected_data_channel2.id())->cast_to<RTCDataChannelStats>());
hbosdbb64d82016-12-21 09:57:461656 ASSERT_TRUE(report->Get(expected_data_channel3.id()));
Yves Gerey665174f2018-06-19 13:03:051657 EXPECT_EQ(
1658 expected_data_channel3,
1659 report->Get(expected_data_channel3.id())->cast_to<RTCDataChannelStats>());
hboscc555c52016-10-18 19:48:311660}
1661
hbosab9f6e42016-10-07 09:18:471662TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidateStats) {
1663 // Candidates in the first transport stats.
Jonas Oreland0d13bbd2022-03-02 10:17:361664 std::unique_ptr<cricket::Candidate> a_local_host = CreateFakeCandidate(
1665 "1.2.3.4", 5, "a_local_host's protocol", rtc::ADAPTER_TYPE_VPN,
1666 cricket::LOCAL_PORT_TYPE, 0, rtc::ADAPTER_TYPE_ETHERNET);
Henrik Boström8dfc90f2022-09-02 07:39:291667 RTCLocalIceCandidateStats expected_a_local_host("I" + a_local_host->id(), 0);
1668 expected_a_local_host.transport_id = "Ta0";
Gary Liu37e489c2017-11-21 18:49:361669 expected_a_local_host.network_type = "vpn";
hbosc42ba322016-12-21 11:31:451670 expected_a_local_host.ip = "1.2.3.4";
Philipp Hanckea9ba4502021-03-22 12:22:541671 expected_a_local_host.address = "1.2.3.4";
hbosc42ba322016-12-21 11:31:451672 expected_a_local_host.port = 5;
1673 expected_a_local_host.protocol = "a_local_host's protocol";
1674 expected_a_local_host.candidate_type = "host";
1675 expected_a_local_host.priority = 0;
Jonas Oreland0d13bbd2022-03-02 10:17:361676 expected_a_local_host.vpn = true;
1677 expected_a_local_host.network_adapter_type = RTCNetworkAdapterType::kEthernet;
Philipp Hancke0e3cd632022-09-27 08:23:091678 expected_a_local_host.foundation = "foundationIsAString";
1679 expected_a_local_host.username_fragment = "iceusernamefragment";
hbosc42ba322016-12-21 11:31:451680
hbosab9f6e42016-10-07 09:18:471681 std::unique_ptr<cricket::Candidate> a_remote_srflx = CreateFakeCandidate(
Gary Liu37e489c2017-11-21 18:49:361682 "6.7.8.9", 10, "remote_srflx's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
1683 cricket::STUN_PORT_TYPE, 1);
Henrik Boström8dfc90f2022-09-02 07:39:291684 RTCRemoteIceCandidateStats expected_a_remote_srflx("I" + a_remote_srflx->id(),
1685 0);
1686 expected_a_remote_srflx.transport_id = "Ta0";
hbosc42ba322016-12-21 11:31:451687 expected_a_remote_srflx.ip = "6.7.8.9";
Philipp Hanckea9ba4502021-03-22 12:22:541688 expected_a_remote_srflx.address = "6.7.8.9";
hbosc42ba322016-12-21 11:31:451689 expected_a_remote_srflx.port = 10;
1690 expected_a_remote_srflx.protocol = "remote_srflx's protocol";
1691 expected_a_remote_srflx.candidate_type = "srflx";
1692 expected_a_remote_srflx.priority = 1;
Philipp Hancke0e3cd632022-09-27 08:23:091693 expected_a_remote_srflx.foundation = "foundationIsAString";
1694 expected_a_remote_srflx.username_fragment = "iceusernamefragment";
hbosc42ba322016-12-21 11:31:451695
hbosab9f6e42016-10-07 09:18:471696 std::unique_ptr<cricket::Candidate> a_local_prflx = CreateFakeCandidate(
Jonas Oreland0d13bbd2022-03-02 10:17:361697 "11.12.13.14", 15, "a_local_prflx's protocol",
1698 rtc::ADAPTER_TYPE_CELLULAR_2G, cricket::PRFLX_PORT_TYPE, 2);
Henrik Boström8dfc90f2022-09-02 07:39:291699 RTCLocalIceCandidateStats expected_a_local_prflx("I" + a_local_prflx->id(),
1700 0);
1701 expected_a_local_prflx.transport_id = "Ta0";
Gary Liu37e489c2017-11-21 18:49:361702 expected_a_local_prflx.network_type = "cellular";
hbosc42ba322016-12-21 11:31:451703 expected_a_local_prflx.ip = "11.12.13.14";
Philipp Hanckea9ba4502021-03-22 12:22:541704 expected_a_local_prflx.address = "11.12.13.14";
hbosc42ba322016-12-21 11:31:451705 expected_a_local_prflx.port = 15;
1706 expected_a_local_prflx.protocol = "a_local_prflx's protocol";
1707 expected_a_local_prflx.candidate_type = "prflx";
1708 expected_a_local_prflx.priority = 2;
Jonas Oreland0d13bbd2022-03-02 10:17:361709 expected_a_local_prflx.vpn = false;
1710 expected_a_local_prflx.network_adapter_type =
1711 RTCNetworkAdapterType::kCellular2g;
Philipp Hancke0e3cd632022-09-27 08:23:091712 expected_a_local_prflx.foundation = "foundationIsAString";
1713 expected_a_local_prflx.username_fragment = "iceusernamefragment";
hbosc42ba322016-12-21 11:31:451714
hbosab9f6e42016-10-07 09:18:471715 std::unique_ptr<cricket::Candidate> a_remote_relay = CreateFakeCandidate(
Gary Liu37e489c2017-11-21 18:49:361716 "16.17.18.19", 20, "a_remote_relay's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
1717 cricket::RELAY_PORT_TYPE, 3);
Henrik Boström8dfc90f2022-09-02 07:39:291718 RTCRemoteIceCandidateStats expected_a_remote_relay("I" + a_remote_relay->id(),
1719 0);
1720 expected_a_remote_relay.transport_id = "Ta0";
hbosc42ba322016-12-21 11:31:451721 expected_a_remote_relay.ip = "16.17.18.19";
Philipp Hanckea9ba4502021-03-22 12:22:541722 expected_a_remote_relay.address = "16.17.18.19";
hbosc42ba322016-12-21 11:31:451723 expected_a_remote_relay.port = 20;
1724 expected_a_remote_relay.protocol = "a_remote_relay's protocol";
1725 expected_a_remote_relay.candidate_type = "relay";
1726 expected_a_remote_relay.priority = 3;
Philipp Hancke0e3cd632022-09-27 08:23:091727 expected_a_remote_relay.foundation = "foundationIsAString";
1728 expected_a_remote_relay.username_fragment = "iceusernamefragment";
hbosc42ba322016-12-21 11:31:451729
Philipp Hancke95513752018-09-27 12:40:081730 std::unique_ptr<cricket::Candidate> a_local_relay = CreateFakeCandidate(
1731 "16.17.18.19", 21, "a_local_relay's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
1732 cricket::RELAY_PORT_TYPE, 1);
1733 a_local_relay->set_relay_protocol("tcp");
Philipp Hancke05b29c72022-02-02 11:06:151734 a_local_relay->set_url("turn:url1");
Philipp Hancke95513752018-09-27 12:40:081735
Henrik Boström8dfc90f2022-09-02 07:39:291736 RTCLocalIceCandidateStats expected_a_local_relay("I" + a_local_relay->id(),
1737 0);
1738 expected_a_local_relay.transport_id = "Ta0";
Philipp Hanckefbd52c02021-11-10 22:02:171739 expected_a_local_relay.network_type = "unknown";
Philipp Hancke95513752018-09-27 12:40:081740 expected_a_local_relay.ip = "16.17.18.19";
Philipp Hanckea9ba4502021-03-22 12:22:541741 expected_a_local_relay.address = "16.17.18.19";
Philipp Hancke95513752018-09-27 12:40:081742 expected_a_local_relay.port = 21;
1743 expected_a_local_relay.protocol = "a_local_relay's protocol";
1744 expected_a_local_relay.relay_protocol = "tcp";
1745 expected_a_local_relay.candidate_type = "relay";
1746 expected_a_local_relay.priority = 1;
Philipp Hancke05b29c72022-02-02 11:06:151747 expected_a_local_relay.url = "turn:url1";
Jonas Oreland0d13bbd2022-03-02 10:17:361748 expected_a_local_relay.vpn = false;
1749 expected_a_local_relay.network_adapter_type = RTCNetworkAdapterType::kUnknown;
Philipp Hancke0e3cd632022-09-27 08:23:091750 expected_a_local_relay.foundation = "foundationIsAString";
1751 expected_a_local_relay.username_fragment = "iceusernamefragment";
Philipp Hancke95513752018-09-27 12:40:081752
Philipp Hancke21c4b1e2021-11-11 06:45:591753 std::unique_ptr<cricket::Candidate> a_local_relay_prflx = CreateFakeCandidate(
1754 "11.12.13.20", 22, "a_local_relay_prflx's protocol",
1755 rtc::ADAPTER_TYPE_UNKNOWN, cricket::PRFLX_PORT_TYPE, 1);
1756 a_local_relay_prflx->set_relay_protocol("udp");
1757
1758 RTCLocalIceCandidateStats expected_a_local_relay_prflx(
Henrik Boström8dfc90f2022-09-02 07:39:291759 "I" + a_local_relay_prflx->id(), 0);
1760 expected_a_local_relay_prflx.transport_id = "Ta0";
Philipp Hancke21c4b1e2021-11-11 06:45:591761 expected_a_local_relay_prflx.network_type = "unknown";
1762 expected_a_local_relay_prflx.ip = "11.12.13.20";
1763 expected_a_local_relay_prflx.address = "11.12.13.20";
1764 expected_a_local_relay_prflx.port = 22;
1765 expected_a_local_relay_prflx.protocol = "a_local_relay_prflx's protocol";
1766 expected_a_local_relay_prflx.relay_protocol = "udp";
1767 expected_a_local_relay_prflx.candidate_type = "prflx";
1768 expected_a_local_relay_prflx.priority = 1;
Jonas Oreland0d13bbd2022-03-02 10:17:361769 expected_a_local_relay_prflx.vpn = false;
1770 expected_a_local_relay_prflx.network_adapter_type =
1771 RTCNetworkAdapterType::kUnknown;
Philipp Hancke0e3cd632022-09-27 08:23:091772 expected_a_local_relay_prflx.foundation = "foundationIsAString";
1773 expected_a_local_relay_prflx.username_fragment = "iceusernamefragment";
Philipp Hancke21c4b1e2021-11-11 06:45:591774
Philipp Hancke6e57ca22022-06-09 13:58:181775 // A non-paired local candidate.
1776 std::unique_ptr<cricket::Candidate> a_local_host_not_paired =
1777 CreateFakeCandidate("1.2.3.4", 4404, "a_local_host_not_paired's protocol",
1778 rtc::ADAPTER_TYPE_VPN, cricket::LOCAL_PORT_TYPE, 0,
1779 rtc::ADAPTER_TYPE_ETHERNET);
1780 RTCLocalIceCandidateStats expected_a_local_host_not_paired(
Henrik Boström8dfc90f2022-09-02 07:39:291781 "I" + a_local_host_not_paired->id(), 0);
1782 expected_a_local_host_not_paired.transport_id = "Ta0";
Philipp Hancke6e57ca22022-06-09 13:58:181783 expected_a_local_host_not_paired.network_type = "vpn";
1784 expected_a_local_host_not_paired.ip = "1.2.3.4";
1785 expected_a_local_host_not_paired.address = "1.2.3.4";
1786 expected_a_local_host_not_paired.port = 4404;
1787 expected_a_local_host_not_paired.protocol =
1788 "a_local_host_not_paired's protocol";
1789 expected_a_local_host_not_paired.candidate_type = "host";
1790 expected_a_local_host_not_paired.priority = 0;
1791 expected_a_local_host_not_paired.vpn = true;
1792 expected_a_local_host_not_paired.network_adapter_type =
1793 RTCNetworkAdapterType::kEthernet;
Philipp Hancke0e3cd632022-09-27 08:23:091794 expected_a_local_host_not_paired.foundation = "foundationIsAString";
1795 expected_a_local_host_not_paired.username_fragment = "iceusernamefragment";
Philipp Hancke6e57ca22022-06-09 13:58:181796
hbosab9f6e42016-10-07 09:18:471797 // Candidates in the second transport stats.
Gary Liu37e489c2017-11-21 18:49:361798 std::unique_ptr<cricket::Candidate> b_local =
1799 CreateFakeCandidate("42.42.42.42", 42, "b_local's protocol",
1800 rtc::ADAPTER_TYPE_WIFI, cricket::LOCAL_PORT_TYPE, 42);
Henrik Boström8dfc90f2022-09-02 07:39:291801 RTCLocalIceCandidateStats expected_b_local("I" + b_local->id(), 0);
1802 expected_b_local.transport_id = "Tb0";
Gary Liu37e489c2017-11-21 18:49:361803 expected_b_local.network_type = "wifi";
hbosc42ba322016-12-21 11:31:451804 expected_b_local.ip = "42.42.42.42";
Philipp Hanckea9ba4502021-03-22 12:22:541805 expected_b_local.address = "42.42.42.42";
hbosc42ba322016-12-21 11:31:451806 expected_b_local.port = 42;
1807 expected_b_local.protocol = "b_local's protocol";
1808 expected_b_local.candidate_type = "host";
1809 expected_b_local.priority = 42;
Jonas Oreland0d13bbd2022-03-02 10:17:361810 expected_b_local.vpn = false;
1811 expected_b_local.network_adapter_type = RTCNetworkAdapterType::kWifi;
Philipp Hancke0e3cd632022-09-27 08:23:091812 expected_b_local.foundation = "foundationIsAString";
1813 expected_b_local.username_fragment = "iceusernamefragment";
hbosc42ba322016-12-21 11:31:451814
hbosab9f6e42016-10-07 09:18:471815 std::unique_ptr<cricket::Candidate> b_remote = CreateFakeCandidate(
Gary Liu37e489c2017-11-21 18:49:361816 "42.42.42.42", 42, "b_remote's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
1817 cricket::LOCAL_PORT_TYPE, 42);
Henrik Boström8dfc90f2022-09-02 07:39:291818 RTCRemoteIceCandidateStats expected_b_remote("I" + b_remote->id(), 0);
1819 expected_b_remote.transport_id = "Tb0";
hbosc42ba322016-12-21 11:31:451820 expected_b_remote.ip = "42.42.42.42";
Philipp Hanckea9ba4502021-03-22 12:22:541821 expected_b_remote.address = "42.42.42.42";
hbosc42ba322016-12-21 11:31:451822 expected_b_remote.port = 42;
1823 expected_b_remote.protocol = "b_remote's protocol";
1824 expected_b_remote.candidate_type = "host";
1825 expected_b_remote.priority = 42;
Philipp Hancke0e3cd632022-09-27 08:23:091826 expected_b_remote.foundation = "foundationIsAString";
1827 expected_b_remote.username_fragment = "iceusernamefragment";
hbosab9f6e42016-10-07 09:18:471828
Philipp Hancke95513752018-09-27 12:40:081829 // Add candidate pairs to connection.
hbosab9f6e42016-10-07 09:18:471830 cricket::TransportChannelStats a_transport_channel_stats;
Jonas Oreland149dc722019-08-28 06:10:271831 a_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
hbosab9f6e42016-10-07 09:18:471832 cricket::ConnectionInfo());
Jonas Oreland149dc722019-08-28 06:10:271833 a_transport_channel_stats.ice_transport_stats.connection_infos[0]
1834 .local_candidate = *a_local_host.get();
1835 a_transport_channel_stats.ice_transport_stats.connection_infos[0]
1836 .remote_candidate = *a_remote_srflx.get();
1837 a_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
hbosab9f6e42016-10-07 09:18:471838 cricket::ConnectionInfo());
Jonas Oreland149dc722019-08-28 06:10:271839 a_transport_channel_stats.ice_transport_stats.connection_infos[1]
1840 .local_candidate = *a_local_prflx.get();
1841 a_transport_channel_stats.ice_transport_stats.connection_infos[1]
1842 .remote_candidate = *a_remote_relay.get();
1843 a_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
Philipp Hancke95513752018-09-27 12:40:081844 cricket::ConnectionInfo());
Jonas Oreland149dc722019-08-28 06:10:271845 a_transport_channel_stats.ice_transport_stats.connection_infos[2]
1846 .local_candidate = *a_local_relay.get();
1847 a_transport_channel_stats.ice_transport_stats.connection_infos[2]
1848 .remote_candidate = *a_remote_relay.get();
Philipp Hancke21c4b1e2021-11-11 06:45:591849 a_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
1850 cricket::ConnectionInfo());
1851 a_transport_channel_stats.ice_transport_stats.connection_infos[3]
1852 .local_candidate = *a_local_relay_prflx.get();
1853 a_transport_channel_stats.ice_transport_stats.connection_infos[3]
1854 .remote_candidate = *a_remote_relay.get();
Philipp Hancke6e57ca22022-06-09 13:58:181855 a_transport_channel_stats.ice_transport_stats.candidate_stats_list.push_back(
1856 cricket::CandidateStats(*a_local_host_not_paired.get()));
Steve Anton5b387312018-02-03 00:00:201857
1858 pc_->AddVoiceChannel("audio", "a");
1859 pc_->SetTransportStats("a", a_transport_channel_stats);
hbosab9f6e42016-10-07 09:18:471860
1861 cricket::TransportChannelStats b_transport_channel_stats;
Jonas Oreland149dc722019-08-28 06:10:271862 b_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
hbosab9f6e42016-10-07 09:18:471863 cricket::ConnectionInfo());
Jonas Oreland149dc722019-08-28 06:10:271864 b_transport_channel_stats.ice_transport_stats.connection_infos[0]
1865 .local_candidate = *b_local.get();
1866 b_transport_channel_stats.ice_transport_stats.connection_infos[0]
1867 .remote_candidate = *b_remote.get();
hbosab9f6e42016-10-07 09:18:471868
Steve Anton5b387312018-02-03 00:00:201869 pc_->AddVideoChannel("video", "b");
1870 pc_->SetTransportStats("b", b_transport_channel_stats);
hbosab9f6e42016-10-07 09:18:471871
Steve Anton5b387312018-02-03 00:00:201872 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbosc42ba322016-12-21 11:31:451873
hbosb4e426e2017-01-02 17:59:311874 ASSERT_TRUE(report->Get(expected_a_local_host.id()));
Yves Gerey665174f2018-06-19 13:03:051875 EXPECT_EQ(expected_a_local_host, report->Get(expected_a_local_host.id())
1876 ->cast_to<RTCLocalIceCandidateStats>());
Philipp Hancke6e57ca22022-06-09 13:58:181877
1878 ASSERT_TRUE(report->Get(expected_a_local_host_not_paired.id()));
1879 EXPECT_EQ(expected_a_local_host_not_paired,
1880 report->Get(expected_a_local_host_not_paired.id())
1881 ->cast_to<RTCLocalIceCandidateStats>());
1882
hbosb4e426e2017-01-02 17:59:311883 ASSERT_TRUE(report->Get(expected_a_remote_srflx.id()));
hbosc42ba322016-12-21 11:31:451884 EXPECT_EQ(expected_a_remote_srflx,
Yves Gerey665174f2018-06-19 13:03:051885 report->Get(expected_a_remote_srflx.id())
1886 ->cast_to<RTCRemoteIceCandidateStats>());
hbosb4e426e2017-01-02 17:59:311887 ASSERT_TRUE(report->Get(expected_a_local_prflx.id()));
Yves Gerey665174f2018-06-19 13:03:051888 EXPECT_EQ(expected_a_local_prflx, report->Get(expected_a_local_prflx.id())
1889 ->cast_to<RTCLocalIceCandidateStats>());
hbosb4e426e2017-01-02 17:59:311890 ASSERT_TRUE(report->Get(expected_a_remote_relay.id()));
hbosc42ba322016-12-21 11:31:451891 EXPECT_EQ(expected_a_remote_relay,
Yves Gerey665174f2018-06-19 13:03:051892 report->Get(expected_a_remote_relay.id())
1893 ->cast_to<RTCRemoteIceCandidateStats>());
Philipp Hanckefbd52c02021-11-10 22:02:171894 ASSERT_TRUE(report->Get(expected_a_local_relay.id()));
1895 EXPECT_EQ(expected_a_local_relay, report->Get(expected_a_local_relay.id())
1896 ->cast_to<RTCLocalIceCandidateStats>());
Philipp Hancke21c4b1e2021-11-11 06:45:591897 ASSERT_TRUE(report->Get(expected_a_local_relay_prflx.id()));
1898 EXPECT_EQ(expected_a_local_relay_prflx,
1899 report->Get(expected_a_local_relay_prflx.id())
1900 ->cast_to<RTCLocalIceCandidateStats>());
hbosb4e426e2017-01-02 17:59:311901 ASSERT_TRUE(report->Get(expected_b_local.id()));
Yves Gerey665174f2018-06-19 13:03:051902 EXPECT_EQ(
1903 expected_b_local,
1904 report->Get(expected_b_local.id())->cast_to<RTCLocalIceCandidateStats>());
hbosb4e426e2017-01-02 17:59:311905 ASSERT_TRUE(report->Get(expected_b_remote.id()));
Yves Gerey665174f2018-06-19 13:03:051906 EXPECT_EQ(expected_b_remote, report->Get(expected_b_remote.id())
1907 ->cast_to<RTCRemoteIceCandidateStats>());
Henrik Boström8dfc90f2022-09-02 07:39:291908 EXPECT_TRUE(report->Get("Ta0"));
1909 EXPECT_TRUE(report->Get("Tb0"));
hbosab9f6e42016-10-07 09:18:471910}
1911
hbosc47a0c32016-10-11 21:54:491912TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidatePairStats) {
Steve Anton5b387312018-02-03 00:00:201913 const char kTransportName[] = "transport";
hbos338f78a2017-02-07 14:41:211914
Gary Liu37e489c2017-11-21 18:49:361915 std::unique_ptr<cricket::Candidate> local_candidate =
1916 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
1917 cricket::LOCAL_PORT_TYPE, 42);
Philipp Hancke0e3cd632022-09-27 08:23:091918 local_candidate->set_username("local_iceusernamefragment");
1919
hbosc47a0c32016-10-11 21:54:491920 std::unique_ptr<cricket::Candidate> remote_candidate = CreateFakeCandidate(
Gary Liu37e489c2017-11-21 18:49:361921 "42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_UNKNOWN,
Philipp Hancke0e3cd632022-09-27 08:23:091922 cricket::STUN_PORT_TYPE, 42);
1923 remote_candidate->set_related_address(rtc::SocketAddress("192.168.2.1", 43));
1924 remote_candidate->set_username("remote_iceusernamefragment");
hbosc47a0c32016-10-11 21:54:491925
hbosc47a0c32016-10-11 21:54:491926 cricket::ConnectionInfo connection_info;
hbos338f78a2017-02-07 14:41:211927 connection_info.best_connection = false;
hbosc47a0c32016-10-11 21:54:491928 connection_info.local_candidate = *local_candidate.get();
1929 connection_info.remote_candidate = *remote_candidate.get();
1930 connection_info.writable = true;
Taylor Brandstetter79326ea2021-09-28 22:09:531931 connection_info.sent_discarded_packets = 3;
1932 connection_info.sent_total_packets = 10;
1933 connection_info.packets_received = 51;
1934 connection_info.sent_discarded_bytes = 7;
hbosc47a0c32016-10-11 21:54:491935 connection_info.sent_total_bytes = 42;
1936 connection_info.recv_total_bytes = 1234;
hbosbf8d3e52017-02-28 14:34:471937 connection_info.total_round_trip_time_ms = 0;
Danil Chapovalov66cadcc2018-06-19 14:47:431938 connection_info.current_round_trip_time_ms = absl::nullopt;
hbosd82f5122016-12-09 12:12:391939 connection_info.recv_ping_requests = 2020;
Henrik Boström839439a2022-09-06 09:16:361940 connection_info.sent_ping_requests_total = 2222;
hbose448dd52016-12-12 09:22:531941 connection_info.sent_ping_requests_before_first_response = 2000;
hbosc47a0c32016-10-11 21:54:491942 connection_info.recv_ping_responses = 4321;
1943 connection_info.sent_ping_responses = 1000;
hbos06495bc2017-01-02 16:08:181944 connection_info.state = cricket::IceCandidatePairState::IN_PROGRESS;
1945 connection_info.priority = 5555;
hbos92eaec62017-02-27 09:38:081946 connection_info.nominated = false;
Philipp Hancke0487c572022-11-01 16:03:011947 connection_info.last_data_received = Timestamp::Millis(2500);
1948 connection_info.last_data_sent = Timestamp::Millis(5200);
hbosc47a0c32016-10-11 21:54:491949
1950 cricket::TransportChannelStats transport_channel_stats;
hbos0583b282016-11-30 09:50:141951 transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
Jonas Oreland149dc722019-08-28 06:10:271952 transport_channel_stats.ice_transport_stats.connection_infos.push_back(
1953 connection_info);
hbosc47a0c32016-10-11 21:54:491954
Steve Anton5b387312018-02-03 00:00:201955 pc_->AddVideoChannel("video", kTransportName);
1956 pc_->SetTransportStats(kTransportName, transport_channel_stats);
hbosc47a0c32016-10-11 21:54:491957
Steve Anton5b387312018-02-03 00:00:201958 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos0583b282016-11-30 09:50:141959
Henrik Boström8dfc90f2022-09-02 07:39:291960 RTCIceCandidatePairStats expected_pair(
1961 "CP" + local_candidate->id() + "_" + remote_candidate->id(),
1962 report->timestamp_us());
hbos0583b282016-11-30 09:50:141963 expected_pair.transport_id =
Henrik Boström8dfc90f2022-09-02 07:39:291964 "Ttransport" + rtc::ToString(cricket::ICE_CANDIDATE_COMPONENT_RTP);
1965 expected_pair.local_candidate_id = "I" + local_candidate->id();
1966 expected_pair.remote_candidate_id = "I" + remote_candidate->id();
hbos06495bc2017-01-02 16:08:181967 expected_pair.state = RTCStatsIceCandidatePairState::kInProgress;
1968 expected_pair.priority = 5555;
hbos92eaec62017-02-27 09:38:081969 expected_pair.nominated = false;
hbos0583b282016-11-30 09:50:141970 expected_pair.writable = true;
Taylor Brandstetter79326ea2021-09-28 22:09:531971 expected_pair.packets_sent = 7;
1972 expected_pair.packets_received = 51;
1973 expected_pair.packets_discarded_on_send = 3;
hbos0583b282016-11-30 09:50:141974 expected_pair.bytes_sent = 42;
1975 expected_pair.bytes_received = 1234;
Taylor Brandstetter79326ea2021-09-28 22:09:531976 expected_pair.bytes_discarded_on_send = 7;
hbosbf8d3e52017-02-28 14:34:471977 expected_pair.total_round_trip_time = 0.0;
hbosd82f5122016-12-09 12:12:391978 expected_pair.requests_received = 2020;
Henrik Boström839439a2022-09-06 09:16:361979 expected_pair.requests_sent = 2222;
hbos0583b282016-11-30 09:50:141980 expected_pair.responses_received = 4321;
1981 expected_pair.responses_sent = 1000;
Henrik Boström839439a2022-09-06 09:16:361982 expected_pair.consent_requests_sent = (2222 - 2000);
Philipp Hancke0487c572022-11-01 16:03:011983 expected_pair.last_packet_received_timestamp = 2500;
1984 expected_pair.last_packet_sent_timestamp = 5200;
1985
Artem Titovcfea2182021-08-09 23:22:311986 // `expected_pair.current_round_trip_time` should be undefined because the
hbosbf8d3e52017-02-28 14:34:471987 // current RTT is not set.
Artem Titovcfea2182021-08-09 23:22:311988 // `expected_pair.available_[outgoing/incoming]_bitrate` should be undefined
hbos338f78a2017-02-07 14:41:211989 // because is is not the current pair.
hbos0583b282016-11-30 09:50:141990
hbosdbb64d82016-12-21 09:57:461991 ASSERT_TRUE(report->Get(expected_pair.id()));
hbos0583b282016-11-30 09:50:141992 EXPECT_EQ(
1993 expected_pair,
1994 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
hbosb4e426e2017-01-02 17:59:311995 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
hbos0583b282016-11-30 09:50:141996
hbos92eaec62017-02-27 09:38:081997 // Set nominated and "GetStats" again.
Jonas Oreland149dc722019-08-28 06:10:271998 transport_channel_stats.ice_transport_stats.connection_infos[0].nominated =
1999 true;
Steve Anton5b387312018-02-03 00:00:202000 pc_->SetTransportStats(kTransportName, transport_channel_stats);
2001 report = stats_->GetFreshStatsReport();
hbos92eaec62017-02-27 09:38:082002 expected_pair.nominated = true;
2003 ASSERT_TRUE(report->Get(expected_pair.id()));
2004 EXPECT_EQ(
2005 expected_pair,
2006 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
2007 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
2008
hbosbf8d3e52017-02-28 14:34:472009 // Set round trip times and "GetStats" again.
Jonas Oreland149dc722019-08-28 06:10:272010 transport_channel_stats.ice_transport_stats.connection_infos[0]
2011 .total_round_trip_time_ms = 7331;
2012 transport_channel_stats.ice_transport_stats.connection_infos[0]
2013 .current_round_trip_time_ms = 1337;
Steve Anton5b387312018-02-03 00:00:202014 pc_->SetTransportStats(kTransportName, transport_channel_stats);
2015 report = stats_->GetFreshStatsReport();
hbosbf8d3e52017-02-28 14:34:472016 expected_pair.total_round_trip_time = 7.331;
2017 expected_pair.current_round_trip_time = 1.337;
2018 ASSERT_TRUE(report->Get(expected_pair.id()));
2019 EXPECT_EQ(
2020 expected_pair,
2021 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
2022 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
2023
hbos338f78a2017-02-07 14:41:212024 // Make pair the current pair, clear bandwidth and "GetStats" again.
Jonas Oreland149dc722019-08-28 06:10:272025 transport_channel_stats.ice_transport_stats.connection_infos[0]
2026 .best_connection = true;
Steve Anton5b387312018-02-03 00:00:202027 pc_->SetTransportStats(kTransportName, transport_channel_stats);
2028 report = stats_->GetFreshStatsReport();
hbos338f78a2017-02-07 14:41:212029 // |expected_pair.available_[outgoing/incoming]_bitrate| should still be
2030 // undefined because bandwidth is not set.
2031 ASSERT_TRUE(report->Get(expected_pair.id()));
2032 EXPECT_EQ(
2033 expected_pair,
2034 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
2035 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
2036
2037 // Set bandwidth and "GetStats" again.
stefanf79ade12017-06-02 13:44:032038 webrtc::Call::Stats call_stats;
2039 const int kSendBandwidth = 888;
2040 call_stats.send_bandwidth_bps = kSendBandwidth;
2041 const int kRecvBandwidth = 999;
2042 call_stats.recv_bandwidth_bps = kRecvBandwidth;
Steve Anton5b387312018-02-03 00:00:202043 pc_->SetCallStats(call_stats);
2044 report = stats_->GetFreshStatsReport();
stefanf79ade12017-06-02 13:44:032045 expected_pair.available_outgoing_bitrate = kSendBandwidth;
2046 expected_pair.available_incoming_bitrate = kRecvBandwidth;
hbos338f78a2017-02-07 14:41:212047 ASSERT_TRUE(report->Get(expected_pair.id()));
2048 EXPECT_EQ(
2049 expected_pair,
2050 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
2051 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
2052
hbosc42ba322016-12-21 11:31:452053 RTCLocalIceCandidateStats expected_local_candidate(
2054 *expected_pair.local_candidate_id, report->timestamp_us());
hbosb4e426e2017-01-02 17:59:312055 expected_local_candidate.transport_id = *expected_pair.transport_id;
Gary Liu37e489c2017-11-21 18:49:362056 expected_local_candidate.network_type = "wifi";
hbosc42ba322016-12-21 11:31:452057 expected_local_candidate.ip = "42.42.42.42";
Philipp Hanckea9ba4502021-03-22 12:22:542058 expected_local_candidate.address = "42.42.42.42";
hbosc42ba322016-12-21 11:31:452059 expected_local_candidate.port = 42;
2060 expected_local_candidate.protocol = "protocol";
2061 expected_local_candidate.candidate_type = "host";
2062 expected_local_candidate.priority = 42;
Philipp Hancke0e3cd632022-09-27 08:23:092063 expected_local_candidate.foundation = "foundationIsAString";
2064 expected_local_candidate.username_fragment = "local_iceusernamefragment";
Jonas Oreland0d13bbd2022-03-02 10:17:362065 expected_local_candidate.vpn = false;
2066 expected_local_candidate.network_adapter_type = RTCNetworkAdapterType::kWifi;
hbosc42ba322016-12-21 11:31:452067 ASSERT_TRUE(report->Get(expected_local_candidate.id()));
2068 EXPECT_EQ(expected_local_candidate,
Yves Gerey665174f2018-06-19 13:03:052069 report->Get(expected_local_candidate.id())
2070 ->cast_to<RTCLocalIceCandidateStats>());
hbosc42ba322016-12-21 11:31:452071
2072 RTCRemoteIceCandidateStats expected_remote_candidate(
2073 *expected_pair.remote_candidate_id, report->timestamp_us());
hbosb4e426e2017-01-02 17:59:312074 expected_remote_candidate.transport_id = *expected_pair.transport_id;
hbosc42ba322016-12-21 11:31:452075 expected_remote_candidate.ip = "42.42.42.42";
Philipp Hanckea9ba4502021-03-22 12:22:542076 expected_remote_candidate.address = "42.42.42.42";
hbosc42ba322016-12-21 11:31:452077 expected_remote_candidate.port = 42;
2078 expected_remote_candidate.protocol = "protocol";
Philipp Hancke0e3cd632022-09-27 08:23:092079 expected_remote_candidate.candidate_type = "srflx";
hbosc42ba322016-12-21 11:31:452080 expected_remote_candidate.priority = 42;
Philipp Hancke0e3cd632022-09-27 08:23:092081 expected_remote_candidate.foundation = "foundationIsAString";
2082 expected_remote_candidate.username_fragment = "remote_iceusernamefragment";
2083 expected_remote_candidate.related_address = "192.168.2.1";
2084 expected_remote_candidate.related_port = 43;
hbosc42ba322016-12-21 11:31:452085 ASSERT_TRUE(report->Get(expected_remote_candidate.id()));
2086 EXPECT_EQ(expected_remote_candidate,
Yves Gerey665174f2018-06-19 13:03:052087 report->Get(expected_remote_candidate.id())
2088 ->cast_to<RTCRemoteIceCandidateStats>());
hbosc47a0c32016-10-11 21:54:492089}
2090
hbosd565b732016-08-30 21:04:352091TEST_F(RTCStatsCollectorTest, CollectRTCPeerConnectionStats) {
hbosd565b732016-08-30 21:04:352092 {
Steve Anton5b387312018-02-03 00:00:202093 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Henrik Boström8dfc90f2022-09-02 07:39:292094 RTCPeerConnectionStats expected("P", report->timestamp_us());
hbos82ebe022016-11-14 09:41:092095 expected.data_channels_opened = 0;
2096 expected.data_channels_closed = 0;
Henrik Boström8dfc90f2022-09-02 07:39:292097 ASSERT_TRUE(report->Get("P"));
2098 EXPECT_EQ(expected, report->Get("P")->cast_to<RTCPeerConnectionStats>());
hbosd565b732016-08-30 21:04:352099 }
2100
Tomas Gunnarsson7d3cfbf2020-06-15 11:47:422101 // TODO(bugs.webrtc.org/11547): Supply a separate network thread.
Harald Alvestrand9e5aeb92022-05-11 09:35:362102 FakeDataChannelController controller;
Taylor Brandstetter3a034e12020-07-09 22:32:342103 rtc::scoped_refptr<SctpDataChannel> dummy_channel_a = SctpDataChannel::Create(
Harald Alvestrand9e5aeb92022-05-11 09:35:362104 &controller, "DummyChannelA", InternalDataChannelInit(),
Tomas Gunnarsson7d3cfbf2020-06-15 11:47:422105 rtc::Thread::Current(), rtc::Thread::Current());
Mirko Bonadeie0bc8d22022-02-08 07:41:252106 pc_->SignalSctpDataChannelCreated()(dummy_channel_a.get());
Taylor Brandstetter3a034e12020-07-09 22:32:342107 rtc::scoped_refptr<SctpDataChannel> dummy_channel_b = SctpDataChannel::Create(
Harald Alvestrand9e5aeb92022-05-11 09:35:362108 &controller, "DummyChannelB", InternalDataChannelInit(),
Tomas Gunnarsson7d3cfbf2020-06-15 11:47:422109 rtc::Thread::Current(), rtc::Thread::Current());
Mirko Bonadeie0bc8d22022-02-08 07:41:252110 pc_->SignalSctpDataChannelCreated()(dummy_channel_b.get());
hbosd565b732016-08-30 21:04:352111
hbos82ebe022016-11-14 09:41:092112 dummy_channel_a->SignalOpened(dummy_channel_a.get());
2113 // Closing a channel that is not opened should not affect the counts.
2114 dummy_channel_b->SignalClosed(dummy_channel_b.get());
2115
hbosd565b732016-08-30 21:04:352116 {
Steve Anton5b387312018-02-03 00:00:202117 rtc::scoped_refptr<const RTCStatsReport> report =
2118 stats_->GetFreshStatsReport();
Henrik Boström8dfc90f2022-09-02 07:39:292119 RTCPeerConnectionStats expected("P", report->timestamp_us());
hbos82ebe022016-11-14 09:41:092120 expected.data_channels_opened = 1;
2121 expected.data_channels_closed = 0;
Henrik Boström8dfc90f2022-09-02 07:39:292122 ASSERT_TRUE(report->Get("P"));
2123 EXPECT_EQ(expected, report->Get("P")->cast_to<RTCPeerConnectionStats>());
hbos82ebe022016-11-14 09:41:092124 }
2125
2126 dummy_channel_b->SignalOpened(dummy_channel_b.get());
2127 dummy_channel_b->SignalClosed(dummy_channel_b.get());
2128
2129 {
Steve Anton5b387312018-02-03 00:00:202130 rtc::scoped_refptr<const RTCStatsReport> report =
2131 stats_->GetFreshStatsReport();
Henrik Boström8dfc90f2022-09-02 07:39:292132 RTCPeerConnectionStats expected("P", report->timestamp_us());
hbos82ebe022016-11-14 09:41:092133 expected.data_channels_opened = 2;
2134 expected.data_channels_closed = 1;
Henrik Boström8dfc90f2022-09-02 07:39:292135 ASSERT_TRUE(report->Get("P"));
2136 EXPECT_EQ(expected, report->Get("P")->cast_to<RTCPeerConnectionStats>());
hbosd565b732016-08-30 21:04:352137 }
hbos5bf9def2017-03-20 10:14:142138
2139 // Re-opening a data channel (or opening a new data channel that is re-using
2140 // the same address in memory) should increase the opened count.
2141 dummy_channel_b->SignalOpened(dummy_channel_b.get());
2142
2143 {
Steve Anton5b387312018-02-03 00:00:202144 rtc::scoped_refptr<const RTCStatsReport> report =
2145 stats_->GetFreshStatsReport();
Henrik Boström8dfc90f2022-09-02 07:39:292146 RTCPeerConnectionStats expected("P", report->timestamp_us());
hbos5bf9def2017-03-20 10:14:142147 expected.data_channels_opened = 3;
2148 expected.data_channels_closed = 1;
Henrik Boström8dfc90f2022-09-02 07:39:292149 ASSERT_TRUE(report->Get("P"));
2150 EXPECT_EQ(expected, report->Get("P")->cast_to<RTCPeerConnectionStats>());
hbos5bf9def2017-03-20 10:14:142151 }
2152
2153 dummy_channel_a->SignalClosed(dummy_channel_a.get());
2154 dummy_channel_b->SignalClosed(dummy_channel_b.get());
2155
2156 {
Steve Anton5b387312018-02-03 00:00:202157 rtc::scoped_refptr<const RTCStatsReport> report =
2158 stats_->GetFreshStatsReport();
Henrik Boström8dfc90f2022-09-02 07:39:292159 RTCPeerConnectionStats expected("P", report->timestamp_us());
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
hbos09bc1282016-11-08 14:29:222167TEST_F(RTCStatsCollectorTest,
Harald Alvestranda3dab842018-01-14 08:18:582168 CollectLocalRTCMediaStreamStatsAndRTCMediaStreamTrackStats_Audio) {
hbos09bc1282016-11-08 14:29:222169 rtc::scoped_refptr<MediaStream> local_stream =
Seth Hampson845e8782018-03-02 19:34:102170 MediaStream::Create("LocalStreamId");
Steve Anton5b387312018-02-03 00:00:202171 pc_->mutable_local_streams()->AddStream(local_stream);
hbos09bc1282016-11-08 14:29:222172
2173 // Local audio track
hbos9e302742017-01-20 10:47:102174 rtc::scoped_refptr<MediaStreamTrackInterface> local_audio_track =
2175 CreateFakeTrack(cricket::MEDIA_TYPE_AUDIO, "LocalAudioTrackID",
2176 MediaStreamTrackInterface::kEnded);
Harald Alvestrand2f7ad282022-04-21 11:35:432177 local_stream->AddTrack(rtc::scoped_refptr<AudioTrackInterface>(
2178 static_cast<AudioTrackInterface*>(local_audio_track.get())));
hbos9e302742017-01-20 10:47:102179
2180 cricket::VoiceSenderInfo voice_sender_info_ssrc1;
2181 voice_sender_info_ssrc1.local_stats.push_back(cricket::SsrcSenderInfo());
2182 voice_sender_info_ssrc1.local_stats[0].ssrc = 1;
Ivo Creusen56d460902017-11-24 16:29:592183 voice_sender_info_ssrc1.apm_statistics.echo_return_loss = 42.0;
2184 voice_sender_info_ssrc1.apm_statistics.echo_return_loss_enhancement = 52.0;
hbos9e302742017-01-20 10:47:102185
Steve Anton5b387312018-02-03 00:00:202186 stats_->CreateMockRtpSendersReceiversAndChannels(
Harald Alvestranda3dab842018-01-14 08:18:582187 {std::make_pair(local_audio_track.get(), voice_sender_info_ssrc1)}, {},
Seth Hampson13b8bad2018-03-13 23:05:282188 {}, {}, {local_stream->id()}, {});
Harald Alvestranda3dab842018-01-14 08:18:582189
Steve Anton5b387312018-02-03 00:00:202190 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Harald Alvestranda3dab842018-01-14 08:18:582191
Henrik Boström15166b22022-10-19 09:06:582192 DEPRECATED_RTCMediaStreamStats expected_local_stream(
2193 IdForType<DEPRECATED_RTCMediaStreamStats>(report.get()),
2194 report->timestamp_us());
Seth Hampson13b8bad2018-03-13 23:05:282195 expected_local_stream.stream_identifier = local_stream->id();
Harald Alvestranda3dab842018-01-14 08:18:582196 expected_local_stream.track_ids = {
Henrik Boström15166b22022-10-19 09:06:582197 IdForType<DEPRECATED_RTCMediaStreamTrackStats>(report.get())};
Harald Alvestranda3dab842018-01-14 08:18:582198 ASSERT_TRUE(report->Get(expected_local_stream.id()))
2199 << "Did not find " << expected_local_stream.id() << " in "
2200 << report->ToJson();
Henrik Boström15166b22022-10-19 09:06:582201 EXPECT_EQ(expected_local_stream,
2202 report->Get(expected_local_stream.id())
2203 ->cast_to<DEPRECATED_RTCMediaStreamStats>());
Harald Alvestranda3dab842018-01-14 08:18:582204
Henrik Boström15166b22022-10-19 09:06:582205 DEPRECATED_RTCMediaStreamTrackStats expected_local_audio_track_ssrc1(
2206 IdForType<DEPRECATED_RTCMediaStreamTrackStats>(report.get()),
2207 report->timestamp_us(), RTCMediaStreamTrackKind::kAudio);
Harald Alvestranda3dab842018-01-14 08:18:582208 expected_local_audio_track_ssrc1.track_identifier = local_audio_track->id();
Henrik Boström646fda02019-05-22 13:49:422209 expected_local_audio_track_ssrc1.media_source_id =
Henrik Boström8dfc90f2022-09-02 07:39:292210 "SA11"; // Attachment ID = SSRC + 10
Harald Alvestranda3dab842018-01-14 08:18:582211 expected_local_audio_track_ssrc1.remote_source = false;
2212 expected_local_audio_track_ssrc1.ended = true;
2213 expected_local_audio_track_ssrc1.detached = false;
Harald Alvestranda3dab842018-01-14 08:18:582214 expected_local_audio_track_ssrc1.echo_return_loss = 42.0;
2215 expected_local_audio_track_ssrc1.echo_return_loss_enhancement = 52.0;
2216 ASSERT_TRUE(report->Get(expected_local_audio_track_ssrc1.id()))
2217 << "Did not find " << expected_local_audio_track_ssrc1.id() << " in "
2218 << report->ToJson();
2219 EXPECT_EQ(expected_local_audio_track_ssrc1,
2220 report->Get(expected_local_audio_track_ssrc1.id())
Henrik Boström15166b22022-10-19 09:06:582221 ->cast_to<DEPRECATED_RTCMediaStreamTrackStats>());
Harald Alvestranda3dab842018-01-14 08:18:582222}
2223
2224TEST_F(RTCStatsCollectorTest,
2225 CollectRemoteRTCMediaStreamStatsAndRTCMediaStreamTrackStats_Audio) {
Harald Alvestranda3dab842018-01-14 08:18:582226 rtc::scoped_refptr<MediaStream> remote_stream =
Seth Hampson845e8782018-03-02 19:34:102227 MediaStream::Create("RemoteStreamId");
Steve Anton5b387312018-02-03 00:00:202228 pc_->mutable_remote_streams()->AddStream(remote_stream);
Harald Alvestranda3dab842018-01-14 08:18:582229
hbos09bc1282016-11-08 14:29:222230 // Remote audio track
hbos9e302742017-01-20 10:47:102231 rtc::scoped_refptr<MediaStreamTrackInterface> remote_audio_track =
2232 CreateFakeTrack(cricket::MEDIA_TYPE_AUDIO, "RemoteAudioTrackID",
2233 MediaStreamTrackInterface::kLive);
Harald Alvestrand2f7ad282022-04-21 11:35:432234 remote_stream->AddTrack(rtc::scoped_refptr<AudioTrackInterface>(
2235 static_cast<AudioTrackInterface*>(remote_audio_track.get())));
hbos9e302742017-01-20 10:47:102236
2237 cricket::VoiceReceiverInfo voice_receiver_info;
2238 voice_receiver_info.local_stats.push_back(cricket::SsrcReceiverInfo());
2239 voice_receiver_info.local_stats[0].ssrc = 3;
Philipp Hanckeaa83cc72020-10-27 08:50:362240 voice_receiver_info.audio_level = 16383; // [0,32767]
zsteine76bd3a2017-07-14 19:17:492241 voice_receiver_info.total_output_energy = 0.125;
Steve Anton2dbc69f2017-08-25 00:15:132242 voice_receiver_info.total_samples_received = 4567;
zsteine76bd3a2017-07-14 19:17:492243 voice_receiver_info.total_output_duration = 0.25;
Steve Anton2dbc69f2017-08-25 00:15:132244 voice_receiver_info.concealed_samples = 123;
Gustaf Ullberg9a2e9062017-09-18 07:28:202245 voice_receiver_info.concealment_events = 12;
Ivo Creusen8d8ffdb2019-04-30 07:45:212246 voice_receiver_info.inserted_samples_for_deceleration = 987;
2247 voice_receiver_info.removed_samples_for_acceleration = 876;
2248 voice_receiver_info.silent_concealed_samples = 765;
Byoungchan Lee899b29e2021-06-29 13:09:182249 voice_receiver_info.jitter_buffer_delay_seconds = 3.456;
Chen Xing0acffb52019-01-15 14:46:292250 voice_receiver_info.jitter_buffer_emitted_count = 13;
hbos9e302742017-01-20 10:47:102251
Steve Anton5b387312018-02-03 00:00:202252 stats_->CreateMockRtpSendersReceiversAndChannels(
Harald Alvestranda3dab842018-01-14 08:18:582253 {}, {std::make_pair(remote_audio_track.get(), voice_receiver_info)}, {},
2254 {}, {}, {remote_stream});
hbos09bc1282016-11-08 14:29:222255
Steve Anton5b387312018-02-03 00:00:202256 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos09bc1282016-11-08 14:29:222257
Henrik Boström15166b22022-10-19 09:06:582258 DEPRECATED_RTCMediaStreamStats expected_remote_stream(
2259 IdForType<DEPRECATED_RTCMediaStreamStats>(report.get()),
2260 report->timestamp_us());
Seth Hampson13b8bad2018-03-13 23:05:282261 expected_remote_stream.stream_identifier = remote_stream->id();
Niels Möllerafb246b2022-04-20 12:26:502262 expected_remote_stream.track_ids = std::vector<std::string>(
Henrik Boström15166b22022-10-19 09:06:582263 {IdForType<DEPRECATED_RTCMediaStreamTrackStats>(report.get())});
Harald Alvestranda3dab842018-01-14 08:18:582264 ASSERT_TRUE(report->Get(expected_remote_stream.id()))
2265 << "Did not find " << expected_remote_stream.id() << " in "
2266 << report->ToJson();
Henrik Boström15166b22022-10-19 09:06:582267 EXPECT_EQ(expected_remote_stream,
2268 report->Get(expected_remote_stream.id())
2269 ->cast_to<DEPRECATED_RTCMediaStreamStats>());
hbos09bc1282016-11-08 14:29:222270
Henrik Boström15166b22022-10-19 09:06:582271 DEPRECATED_RTCMediaStreamTrackStats expected_remote_audio_track(
2272 IdForType<DEPRECATED_RTCMediaStreamTrackStats>(report.get()),
2273 report->timestamp_us(), RTCMediaStreamTrackKind::kAudio);
hbos09bc1282016-11-08 14:29:222274 expected_remote_audio_track.track_identifier = remote_audio_track->id();
Artem Titovcfea2182021-08-09 23:22:312275 // `expected_remote_audio_track.media_source_id` should be undefined
Henrik Boström646fda02019-05-22 13:49:422276 // because the track is remote.
hbos09bc1282016-11-08 14:29:222277 expected_remote_audio_track.remote_source = true;
2278 expected_remote_audio_track.ended = false;
2279 expected_remote_audio_track.detached = false;
Philipp Hanckeaa83cc72020-10-27 08:50:362280 expected_remote_audio_track.audio_level = 16383.0 / 32767.0; // [0,1]
zsteine76bd3a2017-07-14 19:17:492281 expected_remote_audio_track.total_audio_energy = 0.125;
Steve Anton2dbc69f2017-08-25 00:15:132282 expected_remote_audio_track.total_samples_received = 4567;
zsteine76bd3a2017-07-14 19:17:492283 expected_remote_audio_track.total_samples_duration = 0.25;
Steve Anton2dbc69f2017-08-25 00:15:132284 expected_remote_audio_track.concealed_samples = 123;
Gustaf Ullberg9a2e9062017-09-18 07:28:202285 expected_remote_audio_track.concealment_events = 12;
Ivo Creusen8d8ffdb2019-04-30 07:45:212286 expected_remote_audio_track.inserted_samples_for_deceleration = 987;
2287 expected_remote_audio_track.removed_samples_for_acceleration = 876;
2288 expected_remote_audio_track.silent_concealed_samples = 765;
Byoungchan Lee899b29e2021-06-29 13:09:182289 expected_remote_audio_track.jitter_buffer_delay = 3.456;
Chen Xing0acffb52019-01-15 14:46:292290 expected_remote_audio_track.jitter_buffer_emitted_count = 13;
hbosdbb64d82016-12-21 09:57:462291 ASSERT_TRUE(report->Get(expected_remote_audio_track.id()));
hbos09bc1282016-11-08 14:29:222292 EXPECT_EQ(expected_remote_audio_track,
Yves Gerey665174f2018-06-19 13:03:052293 report->Get(expected_remote_audio_track.id())
Henrik Boström15166b22022-10-19 09:06:582294 ->cast_to<DEPRECATED_RTCMediaStreamTrackStats>());
hbos09bc1282016-11-08 14:29:222295}
2296
2297TEST_F(RTCStatsCollectorTest,
Harald Alvestranda3dab842018-01-14 08:18:582298 CollectLocalRTCMediaStreamStatsAndRTCMediaStreamTrackStats_Video) {
hbos09bc1282016-11-08 14:29:222299 rtc::scoped_refptr<MediaStream> local_stream =
Seth Hampson845e8782018-03-02 19:34:102300 MediaStream::Create("LocalStreamId");
Steve Anton5b387312018-02-03 00:00:202301 pc_->mutable_local_streams()->AddStream(local_stream);
hbos09bc1282016-11-08 14:29:222302
2303 // Local video track
hbos9e302742017-01-20 10:47:102304 rtc::scoped_refptr<MediaStreamTrackInterface> local_video_track =
2305 CreateFakeTrack(cricket::MEDIA_TYPE_VIDEO, "LocalVideoTrackID",
2306 MediaStreamTrackInterface::kLive);
Harald Alvestrand2f7ad282022-04-21 11:35:432307 local_stream->AddTrack(rtc::scoped_refptr<VideoTrackInterface>(
2308 static_cast<VideoTrackInterface*>(local_video_track.get())));
hbos09bc1282016-11-08 14:29:222309
hbos9e302742017-01-20 10:47:102310 cricket::VideoSenderInfo video_sender_info_ssrc1;
2311 video_sender_info_ssrc1.local_stats.push_back(cricket::SsrcSenderInfo());
2312 video_sender_info_ssrc1.local_stats[0].ssrc = 1;
2313 video_sender_info_ssrc1.send_frame_width = 1234;
2314 video_sender_info_ssrc1.send_frame_height = 4321;
hbosfefe0762017-01-20 14:14:252315 video_sender_info_ssrc1.frames_encoded = 11;
Ilya Nikolaevskiy70473fc2018-02-28 15:35:032316 video_sender_info_ssrc1.huge_frames_sent = 1;
hbos9e302742017-01-20 10:47:102317
Steve Anton5b387312018-02-03 00:00:202318 stats_->CreateMockRtpSendersReceiversAndChannels(
Harald Alvestranda3dab842018-01-14 08:18:582319 {}, {},
2320 {std::make_pair(local_video_track.get(), video_sender_info_ssrc1)}, {},
Seth Hampson13b8bad2018-03-13 23:05:282321 {local_stream->id()}, {});
Harald Alvestranda3dab842018-01-14 08:18:582322
Steve Anton5b387312018-02-03 00:00:202323 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Harald Alvestranda3dab842018-01-14 08:18:582324
Henrik Boström15166b22022-10-19 09:06:582325 auto stats_of_my_type =
2326 report->GetStatsOfType<DEPRECATED_RTCMediaStreamStats>();
Mirko Bonadeie12c1fe2018-07-03 10:53:232327 ASSERT_EQ(1U, stats_of_my_type.size()) << "No stream in " << report->ToJson();
Henrik Boström15166b22022-10-19 09:06:582328 auto stats_of_track_type =
2329 report->GetStatsOfType<DEPRECATED_RTCMediaStreamTrackStats>();
Mirko Bonadeie12c1fe2018-07-03 10:53:232330 ASSERT_EQ(1U, stats_of_track_type.size())
Harald Alvestranda3dab842018-01-14 08:18:582331 << "Wrong number of tracks in " << report->ToJson();
2332
Henrik Boström15166b22022-10-19 09:06:582333 DEPRECATED_RTCMediaStreamStats expected_local_stream(
2334 stats_of_my_type[0]->id(), report->timestamp_us());
Seth Hampson13b8bad2018-03-13 23:05:282335 expected_local_stream.stream_identifier = local_stream->id();
Harald Alvestranda3dab842018-01-14 08:18:582336 expected_local_stream.track_ids =
2337 std::vector<std::string>({stats_of_track_type[0]->id()});
2338 ASSERT_TRUE(report->Get(expected_local_stream.id()));
Henrik Boström15166b22022-10-19 09:06:582339 EXPECT_EQ(expected_local_stream,
2340 report->Get(expected_local_stream.id())
2341 ->cast_to<DEPRECATED_RTCMediaStreamStats>());
Harald Alvestranda3dab842018-01-14 08:18:582342
Henrik Boström15166b22022-10-19 09:06:582343 DEPRECATED_RTCMediaStreamTrackStats expected_local_video_track_ssrc1(
Harald Alvestranda3dab842018-01-14 08:18:582344 stats_of_track_type[0]->id(), report->timestamp_us(),
2345 RTCMediaStreamTrackKind::kVideo);
2346 expected_local_video_track_ssrc1.track_identifier = local_video_track->id();
Henrik Boström646fda02019-05-22 13:49:422347 expected_local_video_track_ssrc1.media_source_id =
Henrik Boström8dfc90f2022-09-02 07:39:292348 "SV11"; // Attachment ID = SSRC + 10
Harald Alvestranda3dab842018-01-14 08:18:582349 expected_local_video_track_ssrc1.remote_source = false;
2350 expected_local_video_track_ssrc1.ended = false;
2351 expected_local_video_track_ssrc1.detached = false;
2352 expected_local_video_track_ssrc1.frame_width = 1234;
2353 expected_local_video_track_ssrc1.frame_height = 4321;
2354 expected_local_video_track_ssrc1.frames_sent = 11;
Ilya Nikolaevskiy70473fc2018-02-28 15:35:032355 expected_local_video_track_ssrc1.huge_frames_sent = 1;
Harald Alvestranda3dab842018-01-14 08:18:582356 ASSERT_TRUE(report->Get(expected_local_video_track_ssrc1.id()));
2357 EXPECT_EQ(expected_local_video_track_ssrc1,
2358 report->Get(expected_local_video_track_ssrc1.id())
Henrik Boström15166b22022-10-19 09:06:582359 ->cast_to<DEPRECATED_RTCMediaStreamTrackStats>());
Harald Alvestranda3dab842018-01-14 08:18:582360}
2361
2362TEST_F(RTCStatsCollectorTest,
2363 CollectRemoteRTCMediaStreamStatsAndRTCMediaStreamTrackStats_Video) {
Harald Alvestranda3dab842018-01-14 08:18:582364 rtc::scoped_refptr<MediaStream> remote_stream =
Seth Hampson845e8782018-03-02 19:34:102365 MediaStream::Create("RemoteStreamId");
Steve Anton5b387312018-02-03 00:00:202366 pc_->mutable_remote_streams()->AddStream(remote_stream);
Harald Alvestranda3dab842018-01-14 08:18:582367
hbos9e302742017-01-20 10:47:102368 // Remote video track with values
2369 rtc::scoped_refptr<MediaStreamTrackInterface> remote_video_track_ssrc3 =
2370 CreateFakeTrack(cricket::MEDIA_TYPE_VIDEO, "RemoteVideoTrackID3",
2371 MediaStreamTrackInterface::kEnded);
Harald Alvestrand2f7ad282022-04-21 11:35:432372 remote_stream->AddTrack(rtc::scoped_refptr<VideoTrackInterface>(
2373 static_cast<VideoTrackInterface*>(remote_video_track_ssrc3.get())));
hbos9e302742017-01-20 10:47:102374
2375 cricket::VideoReceiverInfo video_receiver_info_ssrc3;
2376 video_receiver_info_ssrc3.local_stats.push_back(cricket::SsrcReceiverInfo());
2377 video_receiver_info_ssrc3.local_stats[0].ssrc = 3;
2378 video_receiver_info_ssrc3.frame_width = 6789;
2379 video_receiver_info_ssrc3.frame_height = 9876;
Guido Urdaneta67378412019-05-28 15:38:082380 video_receiver_info_ssrc3.jitter_buffer_delay_seconds = 2.5;
2381 video_receiver_info_ssrc3.jitter_buffer_emitted_count = 25;
hbos50cfe1f2017-01-23 15:21:552382 video_receiver_info_ssrc3.frames_received = 1000;
2383 video_receiver_info_ssrc3.frames_decoded = 995;
Johannes Kron0c141c52019-08-26 13:04:432384 video_receiver_info_ssrc3.frames_dropped = 10;
hbos50cfe1f2017-01-23 15:21:552385 video_receiver_info_ssrc3.frames_rendered = 990;
hbos9e302742017-01-20 10:47:102386
Steve Anton5b387312018-02-03 00:00:202387 stats_->CreateMockRtpSendersReceiversAndChannels(
Harald Alvestranda3dab842018-01-14 08:18:582388 {}, {}, {},
Harald Alvestrandc72af932018-01-11 16:18:192389 {std::make_pair(remote_video_track_ssrc3.get(),
Harald Alvestranda3dab842018-01-14 08:18:582390 video_receiver_info_ssrc3)},
2391 {}, {remote_stream});
hbos09bc1282016-11-08 14:29:222392
Steve Anton5b387312018-02-03 00:00:202393 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos09bc1282016-11-08 14:29:222394
Henrik Boström15166b22022-10-19 09:06:582395 auto stats_of_my_type =
2396 report->GetStatsOfType<DEPRECATED_RTCMediaStreamStats>();
Mirko Bonadeie12c1fe2018-07-03 10:53:232397 ASSERT_EQ(1U, stats_of_my_type.size()) << "No stream in " << report->ToJson();
Henrik Boström15166b22022-10-19 09:06:582398 auto stats_of_track_type =
2399 report->GetStatsOfType<DEPRECATED_RTCMediaStreamTrackStats>();
Mirko Bonadeie12c1fe2018-07-03 10:53:232400 ASSERT_EQ(1U, stats_of_track_type.size())
Harald Alvestranda3dab842018-01-14 08:18:582401 << "Wrong number of tracks in " << report->ToJson();
2402 ASSERT_TRUE(*(stats_of_track_type[0]->remote_source));
hbos09bc1282016-11-08 14:29:222403
Henrik Boström15166b22022-10-19 09:06:582404 DEPRECATED_RTCMediaStreamStats expected_remote_stream(
2405 stats_of_my_type[0]->id(), report->timestamp_us());
Seth Hampson13b8bad2018-03-13 23:05:282406 expected_remote_stream.stream_identifier = remote_stream->id();
Harald Alvestranda3dab842018-01-14 08:18:582407 expected_remote_stream.track_ids =
2408 std::vector<std::string>({stats_of_track_type[0]->id()});
hbosdbb64d82016-12-21 09:57:462409 ASSERT_TRUE(report->Get(expected_remote_stream.id()));
Henrik Boström15166b22022-10-19 09:06:582410 EXPECT_EQ(expected_remote_stream,
2411 report->Get(expected_remote_stream.id())
2412 ->cast_to<DEPRECATED_RTCMediaStreamStats>());
hbos09bc1282016-11-08 14:29:222413
Henrik Boström15166b22022-10-19 09:06:582414 DEPRECATED_RTCMediaStreamTrackStats expected_remote_video_track_ssrc3(
Harald Alvestranda3dab842018-01-14 08:18:582415 stats_of_track_type[0]->id(), report->timestamp_us(),
2416 RTCMediaStreamTrackKind::kVideo);
hbos9e302742017-01-20 10:47:102417 expected_remote_video_track_ssrc3.track_identifier =
2418 remote_video_track_ssrc3->id();
Artem Titovcfea2182021-08-09 23:22:312419 // `expected_remote_video_track_ssrc3.media_source_id` should be undefined
Henrik Boström646fda02019-05-22 13:49:422420 // because the track is remote.
hbos9e302742017-01-20 10:47:102421 expected_remote_video_track_ssrc3.remote_source = true;
2422 expected_remote_video_track_ssrc3.ended = true;
2423 expected_remote_video_track_ssrc3.detached = false;
2424 expected_remote_video_track_ssrc3.frame_width = 6789;
2425 expected_remote_video_track_ssrc3.frame_height = 9876;
Guido Urdaneta67378412019-05-28 15:38:082426 expected_remote_video_track_ssrc3.jitter_buffer_delay = 2.5;
2427 expected_remote_video_track_ssrc3.jitter_buffer_emitted_count = 25;
hbos50cfe1f2017-01-23 15:21:552428 expected_remote_video_track_ssrc3.frames_received = 1000;
2429 expected_remote_video_track_ssrc3.frames_decoded = 995;
Johannes Kron0c141c52019-08-26 13:04:432430 expected_remote_video_track_ssrc3.frames_dropped = 10;
Sergey Silkin02371062019-01-31 15:45:422431
hbos9e302742017-01-20 10:47:102432 ASSERT_TRUE(report->Get(expected_remote_video_track_ssrc3.id()));
2433 EXPECT_EQ(expected_remote_video_track_ssrc3,
Yves Gerey665174f2018-06-19 13:03:052434 report->Get(expected_remote_video_track_ssrc3.id())
Henrik Boström15166b22022-10-19 09:06:582435 ->cast_to<DEPRECATED_RTCMediaStreamTrackStats>());
hbos09bc1282016-11-08 14:29:222436}
2437
hboseeafe942016-11-01 10:00:172438TEST_F(RTCStatsCollectorTest, CollectRTCInboundRTPStreamStats_Audio) {
hboseeafe942016-11-01 10:00:172439 cricket::VoiceMediaInfo voice_media_info;
hbos0adb8282016-11-23 10:32:062440
hboseeafe942016-11-01 10:00:172441 voice_media_info.receivers.push_back(cricket::VoiceReceiverInfo());
2442 voice_media_info.receivers[0].local_stats.push_back(
2443 cricket::SsrcReceiverInfo());
2444 voice_media_info.receivers[0].local_stats[0].ssrc = 1;
Harald Alvestrand719487e2017-12-13 11:26:042445 voice_media_info.receivers[0].packets_lost = -1; // Signed per RFC3550
Minyue Li28a2c632021-07-07 13:53:382446 voice_media_info.receivers[0].packets_discarded = 7788;
hboseeafe942016-11-01 10:00:172447 voice_media_info.receivers[0].packets_rcvd = 2;
Jakob Ivarssone54914a2021-07-01 09:16:052448 voice_media_info.receivers[0].nacks_sent = 5;
Ivo Creusen8d8ffdb2019-04-30 07:45:212449 voice_media_info.receivers[0].fec_packets_discarded = 5566;
2450 voice_media_info.receivers[0].fec_packets_received = 6677;
Niels Möllerac0a4cb2019-10-09 13:01:332451 voice_media_info.receivers[0].payload_bytes_rcvd = 3;
2452 voice_media_info.receivers[0].header_and_padding_bytes_rcvd = 4;
Oskar Sundbomcbc71b22017-11-16 09:56:072453 voice_media_info.receivers[0].codec_payload_type = 42;
hboseeafe942016-11-01 10:00:172454 voice_media_info.receivers[0].jitter_ms = 4500;
Eldar Rello4e5bc9f2020-07-06 11:18:072455 voice_media_info.receivers[0].jitter_buffer_delay_seconds = 1.0;
Ivo Creusen11fdb082022-07-04 12:16:392456 voice_media_info.receivers[0].jitter_buffer_target_delay_seconds = 1.1;
Ivo Creusen1a84b562022-07-19 14:33:102457 voice_media_info.receivers[0].jitter_buffer_minimum_delay_seconds = 0.999;
Eldar Rello4e5bc9f2020-07-06 11:18:072458 voice_media_info.receivers[0].jitter_buffer_emitted_count = 2;
2459 voice_media_info.receivers[0].total_samples_received = 3;
2460 voice_media_info.receivers[0].concealed_samples = 4;
2461 voice_media_info.receivers[0].silent_concealed_samples = 5;
2462 voice_media_info.receivers[0].concealment_events = 6;
2463 voice_media_info.receivers[0].inserted_samples_for_deceleration = 7;
2464 voice_media_info.receivers[0].removed_samples_for_acceleration = 8;
Philipp Hanckeaa83cc72020-10-27 08:50:362465 voice_media_info.receivers[0].audio_level = 14442; // [0,32767]
Eldar Rello4e5bc9f2020-07-06 11:18:072466 voice_media_info.receivers[0].total_output_energy = 10.0;
2467 voice_media_info.receivers[0].total_output_duration = 11.0;
Henrik Boström2fb83072022-10-06 11:37:112468 voice_media_info.receivers[0].jitter_buffer_flushes = 7;
2469 voice_media_info.receivers[0].delayed_packet_outage_samples = 15;
2470 voice_media_info.receivers[0].relative_packet_arrival_delay_seconds = 16;
2471 voice_media_info.receivers[0].interruption_count = 7788;
2472 voice_media_info.receivers[0].total_interruption_duration_ms = 778899;
Eldar Rello4e5bc9f2020-07-06 11:18:072473
Henrik Boström01738c62019-04-15 15:32:002474 voice_media_info.receivers[0].last_packet_received_timestamp_ms =
2475 absl::nullopt;
hbos0adb8282016-11-23 10:32:062476
2477 RtpCodecParameters codec_parameters;
2478 codec_parameters.payload_type = 42;
deadbeefe702b302017-02-04 20:09:012479 codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
2480 codec_parameters.name = "dummy";
Oskar Sundbomcbc71b22017-11-16 09:56:072481 codec_parameters.clock_rate = 0;
hbos0adb8282016-11-23 10:32:062482 voice_media_info.receive_codecs.insert(
2483 std::make_pair(codec_parameters.payload_type, codec_parameters));
2484
Tommi19015512022-02-02 10:49:352485 auto* voice_media_channel =
2486 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Henrik Boström5b3541f2018-03-19 12:52:562487 stats_->SetupRemoteTrackAndReceiver(
2488 cricket::MEDIA_TYPE_AUDIO, "RemoteAudioTrackID", "RemoteStreamId", 1);
hboseeafe942016-11-01 10:00:172489
Steve Anton5b387312018-02-03 00:00:202490 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hboseeafe942016-11-01 10:00:172491
Henrik Boström15166b22022-10-19 09:06:582492 auto stats_of_track_type =
2493 report->GetStatsOfType<DEPRECATED_RTCMediaStreamTrackStats>();
Mirko Bonadeie12c1fe2018-07-03 10:53:232494 ASSERT_EQ(1U, stats_of_track_type.size());
Harald Alvestranda3dab842018-01-14 08:18:582495
Henrik Boströmb43e3bb2022-09-26 10:36:442496 RTCInboundRTPStreamStats expected_audio("ITTransportName1A1",
2497 report->timestamp_us());
hbos3443bb72017-02-07 14:28:112498 expected_audio.ssrc = 1;
hboseeafe942016-11-01 10:00:172499 expected_audio.media_type = "audio";
Philipp Hancke3bc01662018-08-28 12:55:032500 expected_audio.kind = "audio";
Henrik Boströma6c7d5c2022-06-16 14:55:312501 expected_audio.track_identifier = "RemoteAudioTrackID";
Henrik Boström1ab61882022-06-16 15:07:332502 expected_audio.mid = "AudioMid";
Harald Alvestranda3dab842018-01-14 08:18:582503 expected_audio.track_id = stats_of_track_type[0]->id();
Henrik Boström8dfc90f2022-09-02 07:39:292504 expected_audio.transport_id = "TTransportName1";
2505 expected_audio.codec_id = "CITTransportName1_42";
hboseeafe942016-11-01 10:00:172506 expected_audio.packets_received = 2;
Jakob Ivarssone54914a2021-07-01 09:16:052507 expected_audio.nack_count = 5;
Ivo Creusen8d8ffdb2019-04-30 07:45:212508 expected_audio.fec_packets_discarded = 5566;
2509 expected_audio.fec_packets_received = 6677;
hboseeafe942016-11-01 10:00:172510 expected_audio.bytes_received = 3;
Niels Möllerac0a4cb2019-10-09 13:01:332511 expected_audio.header_bytes_received = 4;
Harald Alvestrand719487e2017-12-13 11:26:042512 expected_audio.packets_lost = -1;
Minyue Li28a2c632021-07-07 13:53:382513 expected_audio.packets_discarded = 7788;
Artem Titovcfea2182021-08-09 23:22:312514 // `expected_audio.last_packet_received_timestamp` should be undefined.
hboseeafe942016-11-01 10:00:172515 expected_audio.jitter = 4.5;
Eldar Rello4e5bc9f2020-07-06 11:18:072516 expected_audio.jitter_buffer_delay = 1.0;
Ivo Creusen11fdb082022-07-04 12:16:392517 expected_audio.jitter_buffer_target_delay = 1.1;
Ivo Creusen1a84b562022-07-19 14:33:102518 expected_audio.jitter_buffer_minimum_delay = 0.999;
Eldar Rello4e5bc9f2020-07-06 11:18:072519 expected_audio.jitter_buffer_emitted_count = 2;
2520 expected_audio.total_samples_received = 3;
2521 expected_audio.concealed_samples = 4;
2522 expected_audio.silent_concealed_samples = 5;
2523 expected_audio.concealment_events = 6;
2524 expected_audio.inserted_samples_for_deceleration = 7;
2525 expected_audio.removed_samples_for_acceleration = 8;
Philipp Hanckeaa83cc72020-10-27 08:50:362526 expected_audio.audio_level = 14442.0 / 32767.0; // [0,1]
Eldar Rello4e5bc9f2020-07-06 11:18:072527 expected_audio.total_audio_energy = 10.0;
2528 expected_audio.total_samples_duration = 11.0;
Henrik Boström2fb83072022-10-06 11:37:112529 expected_audio.jitter_buffer_flushes = 7;
2530 expected_audio.delayed_packet_outage_samples = 15;
2531 expected_audio.relative_packet_arrival_delay = 16;
2532 expected_audio.interruption_count = 7788;
2533 expected_audio.total_interruption_duration = 778.899;
Eldar Rello4e5bc9f2020-07-06 11:18:072534
nissec8ee8822017-01-18 15:20:552535 ASSERT_TRUE(report->Get(expected_audio.id()));
hbosa51d4f32017-02-16 13:34:482536 EXPECT_EQ(
2537 report->Get(expected_audio.id())->cast_to<RTCInboundRTPStreamStats>(),
2538 expected_audio);
Henrik Boström01738c62019-04-15 15:32:002539
2540 // Set previously undefined values and "GetStats" again.
2541 voice_media_info.receivers[0].last_packet_received_timestamp_ms = 3000;
Alessio Bazzicac366d512021-03-22 14:36:532542 expected_audio.last_packet_received_timestamp = 3000.0;
Åsa Perssonfcf79cc2019-10-22 13:23:442543 voice_media_info.receivers[0].estimated_playout_ntp_timestamp_ms = 4567;
2544 expected_audio.estimated_playout_timestamp = 4567;
Henrik Boström01738c62019-04-15 15:32:002545 voice_media_channel->SetStats(voice_media_info);
2546
2547 report = stats_->GetFreshStatsReport();
2548
2549 ASSERT_TRUE(report->Get(expected_audio.id()));
2550 EXPECT_EQ(
2551 report->Get(expected_audio.id())->cast_to<RTCInboundRTPStreamStats>(),
2552 expected_audio);
hbosb0ae9202017-01-27 14:35:162553 EXPECT_TRUE(report->Get(*expected_audio.track_id));
hbos84abeb12017-01-16 14:16:442554 EXPECT_TRUE(report->Get(*expected_audio.transport_id));
2555 EXPECT_TRUE(report->Get(*expected_audio.codec_id));
hboseeafe942016-11-01 10:00:172556}
2557
2558TEST_F(RTCStatsCollectorTest, CollectRTCInboundRTPStreamStats_Video) {
hboseeafe942016-11-01 10:00:172559 cricket::VideoMediaInfo video_media_info;
hbos0adb8282016-11-23 10:32:062560
hboseeafe942016-11-01 10:00:172561 video_media_info.receivers.push_back(cricket::VideoReceiverInfo());
2562 video_media_info.receivers[0].local_stats.push_back(
2563 cricket::SsrcReceiverInfo());
2564 video_media_info.receivers[0].local_stats[0].ssrc = 1;
2565 video_media_info.receivers[0].packets_rcvd = 2;
hbos02cd4d62016-12-09 12:19:442566 video_media_info.receivers[0].packets_lost = 42;
Niels Möllerac0a4cb2019-10-09 13:01:332567 video_media_info.receivers[0].payload_bytes_rcvd = 3;
2568 video_media_info.receivers[0].header_and_padding_bytes_rcvd = 12;
Oskar Sundbomcbc71b22017-11-16 09:56:072569 video_media_info.receivers[0].codec_payload_type = 42;
hbos820f5782016-11-22 11:16:502570 video_media_info.receivers[0].firs_sent = 5;
2571 video_media_info.receivers[0].plis_sent = 6;
2572 video_media_info.receivers[0].nacks_sent = 7;
Eldar Rello4e5bc9f2020-07-06 11:18:072573 video_media_info.receivers[0].frames_received = 8;
2574 video_media_info.receivers[0].frames_decoded = 9;
Rasmus Brandt2efae772019-06-27 12:29:342575 video_media_info.receivers[0].key_frames_decoded = 3;
Eldar Rello4e5bc9f2020-07-06 11:18:072576 video_media_info.receivers[0].frames_dropped = 13;
Danil Chapovalov66cadcc2018-06-19 14:47:432577 video_media_info.receivers[0].qp_sum = absl::nullopt;
Philipp Hancked970b092022-06-17 05:34:232578 video_media_info.receivers[0].total_decode_time =
2579 webrtc::TimeDelta::Seconds(9);
Philipp Hanckea16a6a62022-04-25 10:21:302580 video_media_info.receivers[0].total_processing_delay =
2581 webrtc::TimeDelta::Millis(600);
Philipp Hancke0359ba22022-05-05 13:55:362582 video_media_info.receivers[0].total_assembly_time =
2583 webrtc::TimeDelta::Millis(500);
2584 video_media_info.receivers[0].frames_assembled_from_multiple_packets = 23;
Johannes Kron00376e12019-11-25 09:25:422585 video_media_info.receivers[0].total_inter_frame_delay = 0.123;
2586 video_media_info.receivers[0].total_squared_inter_frame_delay = 0.00456;
Henrik Boströmc57a28c2022-10-06 09:59:052587 video_media_info.receivers[0].pause_count = 2;
2588 video_media_info.receivers[0].total_pauses_duration_ms = 10000;
2589 video_media_info.receivers[0].freeze_count = 3;
2590 video_media_info.receivers[0].total_freezes_duration_ms = 1000;
Di Wu (RP Room Eng)8af6b492021-02-20 01:34:222591 video_media_info.receivers[0].jitter_ms = 1199;
Byoungchan Lee899b29e2021-06-29 13:09:182592 video_media_info.receivers[0].jitter_buffer_delay_seconds = 3.456;
Ivo Creusen11fdb082022-07-04 12:16:392593 video_media_info.receivers[0].jitter_buffer_target_delay_seconds = 1.1;
Ivo Creusen1a84b562022-07-19 14:33:102594 video_media_info.receivers[0].jitter_buffer_minimum_delay_seconds = 0.999;
Byoungchan Lee899b29e2021-06-29 13:09:182595 video_media_info.receivers[0].jitter_buffer_emitted_count = 13;
Johannes Kron00376e12019-11-25 09:25:422596
Henrik Boström01738c62019-04-15 15:32:002597 video_media_info.receivers[0].last_packet_received_timestamp_ms =
2598 absl::nullopt;
Henrik Boström2e069262019-04-09 11:59:312599 video_media_info.receivers[0].content_type = VideoContentType::UNSPECIFIED;
Åsa Perssonfcf79cc2019-10-22 13:23:442600 video_media_info.receivers[0].estimated_playout_ntp_timestamp_ms =
2601 absl::nullopt;
Henrik Boström6b430862019-08-16 11:09:512602 video_media_info.receivers[0].decoder_implementation_name = "";
Philipp Hancke6fb8d1a2022-05-30 10:37:042603 video_media_info.receivers[0].min_playout_delay_ms = 50;
Evan Shrubsole13c0be42022-10-31 11:03:102604 video_media_info.receivers[0].power_efficient_decoder = false;
hbos0adb8282016-11-23 10:32:062605
Philipp Hancke3719a0c2022-07-04 16:24:462606 // Note: these two values intentionally differ,
2607 // only the decoded one should show up.
2608 video_media_info.receivers[0].framerate_rcvd = 15;
2609 video_media_info.receivers[0].framerate_decoded = 5;
2610
hbos0adb8282016-11-23 10:32:062611 RtpCodecParameters codec_parameters;
2612 codec_parameters.payload_type = 42;
Philipp Hancke3719a0c2022-07-04 16:24:462613 codec_parameters.kind = cricket::MEDIA_TYPE_VIDEO;
deadbeefe702b302017-02-04 20:09:012614 codec_parameters.name = "dummy";
Oskar Sundbomcbc71b22017-11-16 09:56:072615 codec_parameters.clock_rate = 0;
hbos0adb8282016-11-23 10:32:062616 video_media_info.receive_codecs.insert(
2617 std::make_pair(codec_parameters.payload_type, codec_parameters));
2618
Tommi19015512022-02-02 10:49:352619 auto* video_media_channel =
2620 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström5b3541f2018-03-19 12:52:562621 stats_->SetupRemoteTrackAndReceiver(
2622 cricket::MEDIA_TYPE_VIDEO, "RemoteVideoTrackID", "RemoteStreamId", 1);
hboseeafe942016-11-01 10:00:172623
Steve Anton5b387312018-02-03 00:00:202624 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hboseeafe942016-11-01 10:00:172625
Henrik Boströmb43e3bb2022-09-26 10:36:442626 RTCInboundRTPStreamStats expected_video("ITTransportName1V1",
2627 report->timestamp_us());
hbos3443bb72017-02-07 14:28:112628 expected_video.ssrc = 1;
hbos820f5782016-11-22 11:16:502629 expected_video.media_type = "video";
Philipp Hancke3bc01662018-08-28 12:55:032630 expected_video.kind = "video";
Henrik Boströma6c7d5c2022-06-16 14:55:312631 expected_video.track_identifier = "RemoteVideoTrackID";
Henrik Boström1ab61882022-06-16 15:07:332632 expected_video.mid = "VideoMid";
Henrik Boström15166b22022-10-19 09:06:582633 expected_video.track_id =
2634 IdForType<DEPRECATED_RTCMediaStreamTrackStats>(report.get());
Henrik Boström8dfc90f2022-09-02 07:39:292635 expected_video.transport_id = "TTransportName1";
2636 expected_video.codec_id = "CITTransportName1_42";
hbos820f5782016-11-22 11:16:502637 expected_video.fir_count = 5;
2638 expected_video.pli_count = 6;
2639 expected_video.nack_count = 7;
2640 expected_video.packets_received = 2;
2641 expected_video.bytes_received = 3;
Niels Möllerac0a4cb2019-10-09 13:01:332642 expected_video.header_bytes_received = 12;
hbos02cd4d62016-12-09 12:19:442643 expected_video.packets_lost = 42;
Eldar Rello4e5bc9f2020-07-06 11:18:072644 expected_video.frames_received = 8;
2645 expected_video.frames_decoded = 9;
Rasmus Brandt2efae772019-06-27 12:29:342646 expected_video.key_frames_decoded = 3;
Eldar Rello4e5bc9f2020-07-06 11:18:072647 expected_video.frames_dropped = 13;
Artem Titovcfea2182021-08-09 23:22:312648 // `expected_video.qp_sum` should be undefined.
Johannes Kronbfd343b2019-07-01 08:07:502649 expected_video.total_decode_time = 9.0;
Philipp Hanckea16a6a62022-04-25 10:21:302650 expected_video.total_processing_delay = 0.6;
Philipp Hancke0359ba22022-05-05 13:55:362651 expected_video.total_assembly_time = 0.5;
2652 expected_video.frames_assembled_from_multiple_packets = 23;
Johannes Kron00376e12019-11-25 09:25:422653 expected_video.total_inter_frame_delay = 0.123;
2654 expected_video.total_squared_inter_frame_delay = 0.00456;
Henrik Boströmc57a28c2022-10-06 09:59:052655 expected_video.pause_count = 2;
2656 expected_video.total_pauses_duration = 10;
2657 expected_video.freeze_count = 3;
2658 expected_video.total_freezes_duration = 1;
Di Wu (RP Room Eng)8af6b492021-02-20 01:34:222659 expected_video.jitter = 1.199;
Byoungchan Lee899b29e2021-06-29 13:09:182660 expected_video.jitter_buffer_delay = 3.456;
Ivo Creusen11fdb082022-07-04 12:16:392661 expected_video.jitter_buffer_target_delay = 1.1;
Ivo Creusen1a84b562022-07-19 14:33:102662 expected_video.jitter_buffer_minimum_delay = 0.999;
Byoungchan Lee899b29e2021-06-29 13:09:182663 expected_video.jitter_buffer_emitted_count = 13;
Artem Titovcfea2182021-08-09 23:22:312664 // `expected_video.last_packet_received_timestamp` should be undefined.
2665 // `expected_video.content_type` should be undefined.
2666 // `expected_video.decoder_implementation` should be undefined.
Philipp Hancke6fb8d1a2022-05-30 10:37:042667 expected_video.min_playout_delay = 0.05;
Philipp Hancke3719a0c2022-07-04 16:24:462668 expected_video.frames_per_second = 5;
Evan Shrubsole13c0be42022-10-31 11:03:102669 expected_video.power_efficient_decoder = false;
hboseeafe942016-11-01 10:00:172670
nissec8ee8822017-01-18 15:20:552671 ASSERT_TRUE(report->Get(expected_video.id()));
hbosa51d4f32017-02-16 13:34:482672 EXPECT_EQ(
2673 report->Get(expected_video.id())->cast_to<RTCInboundRTPStreamStats>(),
2674 expected_video);
hboseeafe942016-11-01 10:00:172675
hbosa51d4f32017-02-16 13:34:482676 // Set previously undefined values and "GetStats" again.
Oskar Sundbomcbc71b22017-11-16 09:56:072677 video_media_info.receivers[0].qp_sum = 9;
hbosa51d4f32017-02-16 13:34:482678 expected_video.qp_sum = 9;
Åsa Perssonfcf79cc2019-10-22 13:23:442679 video_media_info.receivers[0].last_packet_received_timestamp_ms = 1000;
Alessio Bazzica5cf8c2c2021-03-24 07:51:262680 expected_video.last_packet_received_timestamp = 1000.0;
Henrik Boström2e069262019-04-09 11:59:312681 video_media_info.receivers[0].content_type = VideoContentType::SCREENSHARE;
2682 expected_video.content_type = "screenshare";
Åsa Perssonfcf79cc2019-10-22 13:23:442683 video_media_info.receivers[0].estimated_playout_ntp_timestamp_ms = 1234;
2684 expected_video.estimated_playout_timestamp = 1234;
Henrik Boström6b430862019-08-16 11:09:512685 video_media_info.receivers[0].decoder_implementation_name = "libfoodecoder";
2686 expected_video.decoder_implementation = "libfoodecoder";
Evan Shrubsole13c0be42022-10-31 11:03:102687 video_media_info.receivers[0].power_efficient_decoder = true;
2688 expected_video.power_efficient_decoder = true;
Steve Anton5b387312018-02-03 00:00:202689 video_media_channel->SetStats(video_media_info);
hbosa51d4f32017-02-16 13:34:482690
Steve Anton5b387312018-02-03 00:00:202691 report = stats_->GetFreshStatsReport();
hbosa51d4f32017-02-16 13:34:482692
2693 ASSERT_TRUE(report->Get(expected_video.id()));
2694 EXPECT_EQ(
2695 report->Get(expected_video.id())->cast_to<RTCInboundRTPStreamStats>(),
2696 expected_video);
hbosb0ae9202017-01-27 14:35:162697 EXPECT_TRUE(report->Get(*expected_video.track_id));
hbos84abeb12017-01-16 14:16:442698 EXPECT_TRUE(report->Get(*expected_video.transport_id));
hbosa51d4f32017-02-16 13:34:482699 EXPECT_TRUE(report->Get(*expected_video.codec_id));
hboseeafe942016-11-01 10:00:172700}
2701
Henrik Boströmc5f8f802022-10-19 15:50:092702TEST_F(RTCStatsCollectorTest, CollectGoogTimingFrameInfo) {
2703 cricket::VideoMediaInfo video_media_info;
2704
2705 video_media_info.receivers.push_back(cricket::VideoReceiverInfo());
2706 video_media_info.receivers[0].local_stats.push_back(
2707 cricket::SsrcReceiverInfo());
2708 video_media_info.receivers[0].local_stats[0].ssrc = 1;
2709 TimingFrameInfo timing_frame_info;
2710 timing_frame_info.rtp_timestamp = 1;
2711 timing_frame_info.capture_time_ms = 2;
2712 timing_frame_info.encode_start_ms = 3;
2713 timing_frame_info.encode_finish_ms = 4;
2714 timing_frame_info.packetization_finish_ms = 5;
2715 timing_frame_info.pacer_exit_ms = 6;
2716 timing_frame_info.network_timestamp_ms = 7;
2717 timing_frame_info.network2_timestamp_ms = 8;
2718 timing_frame_info.receive_start_ms = 9;
2719 timing_frame_info.receive_finish_ms = 10;
2720 timing_frame_info.decode_start_ms = 11;
2721 timing_frame_info.decode_finish_ms = 12;
2722 timing_frame_info.render_time_ms = 13;
2723 timing_frame_info.flags = 14;
2724 video_media_info.receivers[0].timing_frame_info = timing_frame_info;
2725
2726 pc_->AddVideoChannel("Mid0", "Transport0", video_media_info);
2727 stats_->SetupRemoteTrackAndReceiver(
2728 cricket::MEDIA_TYPE_VIDEO, "RemoteVideoTrackID", "RemoteStreamId", 1);
2729
2730 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
2731 auto inbound_rtps = report->GetStatsOfType<RTCInboundRTPStreamStats>();
2732 ASSERT_EQ(inbound_rtps.size(), 1u);
2733 ASSERT_TRUE(inbound_rtps[0]->goog_timing_frame_info.is_defined());
2734 EXPECT_EQ(*inbound_rtps[0]->goog_timing_frame_info,
2735 "1,2,3,4,5,6,7,8,9,10,11,12,13,1,0");
2736}
2737
hbos6ded1902016-11-01 08:50:462738TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRTPStreamStats_Audio) {
hbos6ded1902016-11-01 08:50:462739 cricket::VoiceMediaInfo voice_media_info;
hbos0adb8282016-11-23 10:32:062740
hbos6ded1902016-11-01 08:50:462741 voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
2742 voice_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
2743 voice_media_info.senders[0].local_stats[0].ssrc = 1;
2744 voice_media_info.senders[0].packets_sent = 2;
Henrik Boströmaebba7b2022-10-26 14:53:032745 voice_media_info.senders[0].total_packet_send_delay = TimeDelta::Seconds(1);
Henrik Boströmcf96e0f2019-04-17 11:51:532746 voice_media_info.senders[0].retransmitted_packets_sent = 20;
Niels Möllerac0a4cb2019-10-09 13:01:332747 voice_media_info.senders[0].payload_bytes_sent = 3;
2748 voice_media_info.senders[0].header_and_padding_bytes_sent = 12;
Henrik Boströmcf96e0f2019-04-17 11:51:532749 voice_media_info.senders[0].retransmitted_bytes_sent = 30;
Jakob Ivarssone91c9922021-07-06 07:55:432750 voice_media_info.senders[0].nacks_rcvd = 31;
Jakob Ivarssonbf087452021-11-11 12:43:492751 voice_media_info.senders[0].target_bitrate = 32000;
Oskar Sundbomcbc71b22017-11-16 09:56:072752 voice_media_info.senders[0].codec_payload_type = 42;
Philipp Hancke684e2412022-07-28 10:41:002753 voice_media_info.senders[0].active = true;
hbos0adb8282016-11-23 10:32:062754
2755 RtpCodecParameters codec_parameters;
2756 codec_parameters.payload_type = 42;
deadbeefe702b302017-02-04 20:09:012757 codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
2758 codec_parameters.name = "dummy";
Oskar Sundbomcbc71b22017-11-16 09:56:072759 codec_parameters.clock_rate = 0;
hbos0adb8282016-11-23 10:32:062760 voice_media_info.send_codecs.insert(
2761 std::make_pair(codec_parameters.payload_type, codec_parameters));
2762
Tommi19015512022-02-02 10:49:352763 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Steve Anton5b387312018-02-03 00:00:202764 stats_->SetupLocalTrackAndSender(cricket::MEDIA_TYPE_AUDIO,
Henrik Boström646fda02019-05-22 13:49:422765 "LocalAudioTrackID", 1, true,
2766 /*attachment_id=*/50);
hbos6ded1902016-11-01 08:50:462767
Steve Anton5b387312018-02-03 00:00:202768 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos6ded1902016-11-01 08:50:462769
Henrik Boströmb43e3bb2022-09-26 10:36:442770 RTCOutboundRTPStreamStats expected_audio("OTTransportName1A1",
2771 report->timestamp_us());
Henrik Boström8dfc90f2022-09-02 07:39:292772 expected_audio.media_source_id = "SA50";
Artem Titovcfea2182021-08-09 23:22:312773 // `expected_audio.remote_id` should be undefined.
Henrik Boström1ab61882022-06-16 15:07:332774 expected_audio.mid = "AudioMid";
hbos3443bb72017-02-07 14:28:112775 expected_audio.ssrc = 1;
hbos6ded1902016-11-01 08:50:462776 expected_audio.media_type = "audio";
Philipp Hancke3bc01662018-08-28 12:55:032777 expected_audio.kind = "audio";
Henrik Boström15166b22022-10-19 09:06:582778 expected_audio.track_id =
2779 IdForType<DEPRECATED_RTCMediaStreamTrackStats>(report.get());
Henrik Boström8dfc90f2022-09-02 07:39:292780 expected_audio.transport_id = "TTransportName1";
2781 expected_audio.codec_id = "COTTransportName1_42";
hbos6ded1902016-11-01 08:50:462782 expected_audio.packets_sent = 2;
Henrik Boströmaebba7b2022-10-26 14:53:032783 expected_audio.total_packet_send_delay = 1;
Henrik Boströmcf96e0f2019-04-17 11:51:532784 expected_audio.retransmitted_packets_sent = 20;
hbos6ded1902016-11-01 08:50:462785 expected_audio.bytes_sent = 3;
Niels Möllerac0a4cb2019-10-09 13:01:332786 expected_audio.header_bytes_sent = 12;
Henrik Boströmcf96e0f2019-04-17 11:51:532787 expected_audio.retransmitted_bytes_sent = 30;
Jakob Ivarssone91c9922021-07-06 07:55:432788 expected_audio.nack_count = 31;
Jakob Ivarssonbf087452021-11-11 12:43:492789 expected_audio.target_bitrate = 32000;
Philipp Hancke684e2412022-07-28 10:41:002790 expected_audio.active = true;
hboscd195be2017-02-07 16:31:272791
hboscd195be2017-02-07 16:31:272792 ASSERT_TRUE(report->Get(expected_audio.id()));
hbosa51d4f32017-02-16 13:34:482793 EXPECT_EQ(
2794 report->Get(expected_audio.id())->cast_to<RTCOutboundRTPStreamStats>(),
2795 expected_audio);
skvladed02c6d2017-02-07 18:45:312796
hbosa51d4f32017-02-16 13:34:482797 ASSERT_TRUE(report->Get(expected_audio.id()));
2798 EXPECT_EQ(
2799 report->Get(expected_audio.id())->cast_to<RTCOutboundRTPStreamStats>(),
2800 expected_audio);
hbosb0ae9202017-01-27 14:35:162801 EXPECT_TRUE(report->Get(*expected_audio.track_id));
hbos84abeb12017-01-16 14:16:442802 EXPECT_TRUE(report->Get(*expected_audio.transport_id));
2803 EXPECT_TRUE(report->Get(*expected_audio.codec_id));
hbos6ded1902016-11-01 08:50:462804}
2805
2806TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRTPStreamStats_Video) {
hbos6ded1902016-11-01 08:50:462807 cricket::VideoMediaInfo video_media_info;
hbos0adb8282016-11-23 10:32:062808
hbos6ded1902016-11-01 08:50:462809 video_media_info.senders.push_back(cricket::VideoSenderInfo());
2810 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
2811 video_media_info.senders[0].local_stats[0].ssrc = 1;
2812 video_media_info.senders[0].firs_rcvd = 2;
2813 video_media_info.senders[0].plis_rcvd = 3;
2814 video_media_info.senders[0].nacks_rcvd = 4;
2815 video_media_info.senders[0].packets_sent = 5;
Henrik Boströmcf96e0f2019-04-17 11:51:532816 video_media_info.senders[0].retransmitted_packets_sent = 50;
Niels Möllerac0a4cb2019-10-09 13:01:332817 video_media_info.senders[0].payload_bytes_sent = 6;
2818 video_media_info.senders[0].header_and_padding_bytes_sent = 12;
Henrik Boströmcf96e0f2019-04-17 11:51:532819 video_media_info.senders[0].retransmitted_bytes_sent = 60;
Oskar Sundbomcbc71b22017-11-16 09:56:072820 video_media_info.senders[0].codec_payload_type = 42;
hbos6769c492017-01-02 16:35:132821 video_media_info.senders[0].frames_encoded = 8;
Rasmus Brandt2efae772019-06-27 12:29:342822 video_media_info.senders[0].key_frames_encoded = 3;
Henrik Boströmf71362f2019-04-08 14:14:232823 video_media_info.senders[0].total_encode_time_ms = 9000;
Henrik Boström23aff9b2019-05-20 13:15:382824 video_media_info.senders[0].total_encoded_bytes_target = 1234;
Henrik Boströmd8199212022-10-26 14:50:532825 video_media_info.senders[0].total_packet_send_delay =
2826 webrtc::TimeDelta::Seconds(10);
Henrik Boströmce33b6a2019-05-28 15:42:382827 video_media_info.senders[0].quality_limitation_reason =
2828 QualityLimitationReason::kBandwidth;
Byoungchan Lee7d235352021-05-28 12:32:042829 video_media_info.senders[0].quality_limitation_durations_ms
2830 [webrtc::QualityLimitationReason::kBandwidth] = 300;
Evan Shrubsolecc62b162019-09-09 09:26:452831 video_media_info.senders[0].quality_limitation_resolution_changes = 56u;
Danil Chapovalov66cadcc2018-06-19 14:47:432832 video_media_info.senders[0].qp_sum = absl::nullopt;
Henrik Boström2e069262019-04-09 11:59:312833 video_media_info.senders[0].content_type = VideoContentType::UNSPECIFIED;
Henrik Boström6b430862019-08-16 11:09:512834 video_media_info.senders[0].encoder_implementation_name = "";
Evan Shrubsole13c0be42022-10-31 11:03:102835 video_media_info.senders[0].power_efficient_encoder = false;
Henrik Boströma0ff50c2020-05-05 13:54:462836 video_media_info.senders[0].send_frame_width = 200;
2837 video_media_info.senders[0].send_frame_height = 100;
2838 video_media_info.senders[0].framerate_sent = 10;
2839 video_media_info.senders[0].frames_sent = 5;
2840 video_media_info.senders[0].huge_frames_sent = 2;
Philipp Hancke684e2412022-07-28 10:41:002841 video_media_info.senders[0].active = false;
Evan Shrubsole9b235cd2022-12-06 10:09:102842 video_media_info.senders[0].scalability_mode = ScalabilityMode::kL3T3_KEY;
Henrik Boströma0ff50c2020-05-05 13:54:462843 video_media_info.aggregated_senders.push_back(video_media_info.senders[0]);
hbos0adb8282016-11-23 10:32:062844 RtpCodecParameters codec_parameters;
2845 codec_parameters.payload_type = 42;
deadbeefe702b302017-02-04 20:09:012846 codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
2847 codec_parameters.name = "dummy";
Oskar Sundbomcbc71b22017-11-16 09:56:072848 codec_parameters.clock_rate = 0;
hbos0adb8282016-11-23 10:32:062849 video_media_info.send_codecs.insert(
2850 std::make_pair(codec_parameters.payload_type, codec_parameters));
2851
Tommi19015512022-02-02 10:49:352852 auto* video_media_channel =
2853 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Steve Anton5b387312018-02-03 00:00:202854 stats_->SetupLocalTrackAndSender(cricket::MEDIA_TYPE_VIDEO,
Henrik Boström646fda02019-05-22 13:49:422855 "LocalVideoTrackID", 1, true,
2856 /*attachment_id=*/50);
hbos6ded1902016-11-01 08:50:462857
Steve Anton5b387312018-02-03 00:00:202858 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos6ded1902016-11-01 08:50:462859
Harald Alvestranda3dab842018-01-14 08:18:582860 auto stats_of_my_type = report->GetStatsOfType<RTCOutboundRTPStreamStats>();
Mirko Bonadeie12c1fe2018-07-03 10:53:232861 ASSERT_EQ(1U, stats_of_my_type.size());
Henrik Boström15166b22022-10-19 09:06:582862 auto stats_of_track_type =
2863 report->GetStatsOfType<DEPRECATED_RTCMediaStreamTrackStats>();
Mirko Bonadeie12c1fe2018-07-03 10:53:232864 ASSERT_EQ(1U, stats_of_track_type.size());
Harald Alvestranda3dab842018-01-14 08:18:582865
2866 RTCOutboundRTPStreamStats expected_video(stats_of_my_type[0]->id(),
2867 report->timestamp_us());
Henrik Boström8dfc90f2022-09-02 07:39:292868 expected_video.media_source_id = "SV50";
Artem Titovcfea2182021-08-09 23:22:312869 // `expected_video.remote_id` should be undefined.
Henrik Boström1ab61882022-06-16 15:07:332870 expected_video.mid = "VideoMid";
hbos3443bb72017-02-07 14:28:112871 expected_video.ssrc = 1;
hbos6ded1902016-11-01 08:50:462872 expected_video.media_type = "video";
Philipp Hancke3bc01662018-08-28 12:55:032873 expected_video.kind = "video";
Harald Alvestranda3dab842018-01-14 08:18:582874 expected_video.track_id = stats_of_track_type[0]->id();
Henrik Boström8dfc90f2022-09-02 07:39:292875 expected_video.transport_id = "TTransportName1";
2876 expected_video.codec_id = "COTTransportName1_42";
hbos6ded1902016-11-01 08:50:462877 expected_video.fir_count = 2;
2878 expected_video.pli_count = 3;
2879 expected_video.nack_count = 4;
2880 expected_video.packets_sent = 5;
Henrik Boströmcf96e0f2019-04-17 11:51:532881 expected_video.retransmitted_packets_sent = 50;
hbos6ded1902016-11-01 08:50:462882 expected_video.bytes_sent = 6;
Niels Möllerac0a4cb2019-10-09 13:01:332883 expected_video.header_bytes_sent = 12;
Henrik Boströmcf96e0f2019-04-17 11:51:532884 expected_video.retransmitted_bytes_sent = 60;
skvladed02c6d2017-02-07 18:45:312885 expected_video.frames_encoded = 8;
Rasmus Brandt2efae772019-06-27 12:29:342886 expected_video.key_frames_encoded = 3;
Henrik Boströmf71362f2019-04-08 14:14:232887 expected_video.total_encode_time = 9.0;
Henrik Boström23aff9b2019-05-20 13:15:382888 expected_video.total_encoded_bytes_target = 1234;
Henrik Boström9fe18342019-05-16 16:38:202889 expected_video.total_packet_send_delay = 10.0;
Henrik Boströmce33b6a2019-05-28 15:42:382890 expected_video.quality_limitation_reason = "bandwidth";
Byoungchan Lee7d235352021-05-28 12:32:042891 expected_video.quality_limitation_durations = std::map<std::string, double>{
Philipp Hancke3fd9cbc2022-01-10 16:41:432892 std::pair<std::string, double>{"bandwidth", 0.3},
Byoungchan Lee7d235352021-05-28 12:32:042893 };
Evan Shrubsolecc62b162019-09-09 09:26:452894 expected_video.quality_limitation_resolution_changes = 56u;
Eldar Rello9276e2c2020-06-10 14:53:392895 expected_video.frame_width = 200u;
2896 expected_video.frame_height = 100u;
2897 expected_video.frames_per_second = 10.0;
2898 expected_video.frames_sent = 5;
2899 expected_video.huge_frames_sent = 2;
Philipp Hancke684e2412022-07-28 10:41:002900 expected_video.active = false;
Evan Shrubsole13c0be42022-10-31 11:03:102901 expected_video.power_efficient_encoder = false;
Evan Shrubsole9b235cd2022-12-06 10:09:102902 expected_video.scalability_mode = "L3T3_KEY";
Artem Titovcfea2182021-08-09 23:22:312903 // `expected_video.content_type` should be undefined.
2904 // `expected_video.qp_sum` should be undefined.
2905 // `expected_video.encoder_implementation` should be undefined.
hboscd195be2017-02-07 16:31:272906 ASSERT_TRUE(report->Get(expected_video.id()));
Harald Alvestranda3dab842018-01-14 08:18:582907
hbosa51d4f32017-02-16 13:34:482908 EXPECT_EQ(
2909 report->Get(expected_video.id())->cast_to<RTCOutboundRTPStreamStats>(),
2910 expected_video);
skvladed02c6d2017-02-07 18:45:312911
hbosa51d4f32017-02-16 13:34:482912 // Set previously undefined values and "GetStats" again.
Oskar Sundbomcbc71b22017-11-16 09:56:072913 video_media_info.senders[0].qp_sum = 9;
hbosa51d4f32017-02-16 13:34:482914 expected_video.qp_sum = 9;
Henrik Boström2e069262019-04-09 11:59:312915 video_media_info.senders[0].content_type = VideoContentType::SCREENSHARE;
2916 expected_video.content_type = "screenshare";
Henrik Boström6b430862019-08-16 11:09:512917 video_media_info.senders[0].encoder_implementation_name = "libfooencoder";
Henrik Boströma0ff50c2020-05-05 13:54:462918 video_media_info.aggregated_senders[0] = video_media_info.senders[0];
Henrik Boström6b430862019-08-16 11:09:512919 expected_video.encoder_implementation = "libfooencoder";
Evan Shrubsole13c0be42022-10-31 11:03:102920 video_media_info.senders[0].power_efficient_encoder = true;
2921 expected_video.power_efficient_encoder = true;
Steve Anton5b387312018-02-03 00:00:202922 video_media_channel->SetStats(video_media_info);
hbosa51d4f32017-02-16 13:34:482923
Steve Anton5b387312018-02-03 00:00:202924 report = stats_->GetFreshStatsReport();
hbosa51d4f32017-02-16 13:34:482925
2926 ASSERT_TRUE(report->Get(expected_video.id()));
2927 EXPECT_EQ(
2928 report->Get(expected_video.id())->cast_to<RTCOutboundRTPStreamStats>(),
2929 expected_video);
hbosb0ae9202017-01-27 14:35:162930 EXPECT_TRUE(report->Get(*expected_video.track_id));
hbos84abeb12017-01-16 14:16:442931 EXPECT_TRUE(report->Get(*expected_video.transport_id));
2932 EXPECT_TRUE(report->Get(*expected_video.codec_id));
hbos6ded1902016-11-01 08:50:462933}
2934
hbos2fa7c672016-10-24 11:00:052935TEST_F(RTCStatsCollectorTest, CollectRTCTransportStats) {
Steve Anton5b387312018-02-03 00:00:202936 const char kTransportName[] = "transport";
2937
2938 pc_->AddVoiceChannel("audio", kTransportName);
2939
Gary Liu37e489c2017-11-21 18:49:362940 std::unique_ptr<cricket::Candidate> rtp_local_candidate =
2941 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
2942 cricket::LOCAL_PORT_TYPE, 42);
hbos2fa7c672016-10-24 11:00:052943 std::unique_ptr<cricket::Candidate> rtp_remote_candidate =
2944 CreateFakeCandidate("42.42.42.42", 42, "protocol",
Gary Liu37e489c2017-11-21 18:49:362945 rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
2946 42);
hbos2fa7c672016-10-24 11:00:052947 std::unique_ptr<cricket::Candidate> rtcp_local_candidate =
Gary Liu37e489c2017-11-21 18:49:362948 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
hbos2fa7c672016-10-24 11:00:052949 cricket::LOCAL_PORT_TYPE, 42);
2950 std::unique_ptr<cricket::Candidate> rtcp_remote_candidate =
2951 CreateFakeCandidate("42.42.42.42", 42, "protocol",
Gary Liu37e489c2017-11-21 18:49:362952 rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
2953 42);
hbos2fa7c672016-10-24 11:00:052954
hbos2fa7c672016-10-24 11:00:052955 cricket::ConnectionInfo rtp_connection_info;
2956 rtp_connection_info.best_connection = false;
2957 rtp_connection_info.local_candidate = *rtp_local_candidate.get();
2958 rtp_connection_info.remote_candidate = *rtp_remote_candidate.get();
2959 rtp_connection_info.sent_total_bytes = 42;
2960 rtp_connection_info.recv_total_bytes = 1337;
Artem Titovedacbd52020-07-06 14:06:372961 rtp_connection_info.sent_total_packets = 3;
2962 rtp_connection_info.sent_discarded_packets = 2;
2963 rtp_connection_info.packets_received = 4;
hbos2fa7c672016-10-24 11:00:052964 cricket::TransportChannelStats rtp_transport_channel_stats;
2965 rtp_transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
Jonas Oreland149dc722019-08-28 06:10:272966 rtp_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
2967 rtp_connection_info);
Mirko Bonadei9f6808b2021-05-21 18:46:092968 rtp_transport_channel_stats.dtls_state = DtlsTransportState::kNew;
Jonas Oreland42da5a92022-03-01 12:55:372969 rtp_transport_channel_stats.ice_transport_stats.bytes_sent = 42;
2970 rtp_transport_channel_stats.ice_transport_stats.packets_sent = 1;
2971 rtp_transport_channel_stats.ice_transport_stats.bytes_received = 1337;
2972 rtp_transport_channel_stats.ice_transport_stats.packets_received = 4;
Jonas Oreland149dc722019-08-28 06:10:272973 rtp_transport_channel_stats.ice_transport_stats
2974 .selected_candidate_pair_changes = 1;
Philipp Hancke95b1a342022-05-05 05:53:542975 rtp_transport_channel_stats.ice_transport_stats.ice_local_username_fragment =
2976 "thelocalufrag";
Steve Anton5b387312018-02-03 00:00:202977 pc_->SetTransportStats(kTransportName, {rtp_transport_channel_stats});
hbos2fa7c672016-10-24 11:00:052978
2979 // Get stats without RTCP, an active connection or certificates.
Steve Anton5b387312018-02-03 00:00:202980 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos0583b282016-11-30 09:50:142981
2982 RTCTransportStats expected_rtp_transport(
Henrik Boström8dfc90f2022-09-02 07:39:292983 "Ttransport" + rtc::ToString(cricket::ICE_CANDIDATE_COMPONENT_RTP),
hbos0583b282016-11-30 09:50:142984 report->timestamp_us());
2985 expected_rtp_transport.bytes_sent = 42;
Artem Titovedacbd52020-07-06 14:06:372986 expected_rtp_transport.packets_sent = 1;
hbos0583b282016-11-30 09:50:142987 expected_rtp_transport.bytes_received = 1337;
Artem Titovedacbd52020-07-06 14:06:372988 expected_rtp_transport.packets_received = 4;
hbos7064d592017-01-16 15:38:022989 expected_rtp_transport.dtls_state = RTCDtlsTransportState::kNew;
Philipp Hancke69c1df22022-04-22 13:46:242990 expected_rtp_transport.dtls_role = RTCDtlsRole::kUnknown;
Jonas Oreland149dc722019-08-28 06:10:272991 expected_rtp_transport.selected_candidate_pair_changes = 1;
Philipp Hanckecc1b9b02022-05-04 16:58:262992 expected_rtp_transport.ice_role = RTCIceRole::kUnknown;
Philipp Hancke95b1a342022-05-05 05:53:542993 expected_rtp_transport.ice_local_username_fragment = "thelocalufrag";
Philipp Hancke1f491572022-05-09 15:43:312994 expected_rtp_transport.ice_state = RTCIceTransportState::kNew;
hbos0583b282016-11-30 09:50:142995
hbosdbb64d82016-12-21 09:57:462996 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
hbos0583b282016-11-30 09:50:142997 EXPECT_EQ(
2998 expected_rtp_transport,
2999 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
hbos2fa7c672016-10-24 11:00:053000
3001 cricket::ConnectionInfo rtcp_connection_info;
3002 rtcp_connection_info.best_connection = false;
3003 rtcp_connection_info.local_candidate = *rtcp_local_candidate.get();
3004 rtcp_connection_info.remote_candidate = *rtcp_remote_candidate.get();
3005 rtcp_connection_info.sent_total_bytes = 1337;
3006 rtcp_connection_info.recv_total_bytes = 42;
Artem Titovedacbd52020-07-06 14:06:373007 rtcp_connection_info.sent_total_packets = 3;
3008 rtcp_connection_info.sent_discarded_packets = 2;
3009 rtcp_connection_info.packets_received = 4;
hbos2fa7c672016-10-24 11:00:053010 cricket::TransportChannelStats rtcp_transport_channel_stats;
3011 rtcp_transport_channel_stats.component =
3012 cricket::ICE_CANDIDATE_COMPONENT_RTCP;
Jonas Oreland149dc722019-08-28 06:10:273013 rtcp_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
3014 rtcp_connection_info);
Mirko Bonadei9f6808b2021-05-21 18:46:093015 rtcp_transport_channel_stats.dtls_state = DtlsTransportState::kConnecting;
Jonas Oreland42da5a92022-03-01 12:55:373016 rtcp_transport_channel_stats.ice_transport_stats.bytes_sent = 1337;
3017 rtcp_transport_channel_stats.ice_transport_stats.packets_sent = 1;
3018 rtcp_transport_channel_stats.ice_transport_stats.bytes_received = 42;
3019 rtcp_transport_channel_stats.ice_transport_stats.packets_received = 4;
Philipp Hancke95b1a342022-05-05 05:53:543020 rtcp_transport_channel_stats.ice_transport_stats.ice_local_username_fragment =
3021 "thelocalufrag";
Philipp Hancke1f491572022-05-09 15:43:313022 rtcp_transport_channel_stats.ice_transport_stats.ice_state =
3023 IceTransportState::kChecking;
Steve Anton5b387312018-02-03 00:00:203024 pc_->SetTransportStats(kTransportName, {rtp_transport_channel_stats,
3025 rtcp_transport_channel_stats});
hbos2fa7c672016-10-24 11:00:053026
hbos2fa7c672016-10-24 11:00:053027 // Get stats with RTCP and without an active connection or certificates.
Steve Anton5b387312018-02-03 00:00:203028 report = stats_->GetFreshStatsReport();
hbos0583b282016-11-30 09:50:143029
3030 RTCTransportStats expected_rtcp_transport(
Henrik Boström8dfc90f2022-09-02 07:39:293031 "Ttransport" + rtc::ToString(cricket::ICE_CANDIDATE_COMPONENT_RTCP),
hbos0583b282016-11-30 09:50:143032 report->timestamp_us());
3033 expected_rtcp_transport.bytes_sent = 1337;
Artem Titovedacbd52020-07-06 14:06:373034 expected_rtcp_transport.packets_sent = 1;
hbos0583b282016-11-30 09:50:143035 expected_rtcp_transport.bytes_received = 42;
Artem Titovedacbd52020-07-06 14:06:373036 expected_rtcp_transport.packets_received = 4;
hbos7064d592017-01-16 15:38:023037 expected_rtcp_transport.dtls_state = RTCDtlsTransportState::kConnecting;
Philipp Hancke69c1df22022-04-22 13:46:243038 expected_rtcp_transport.dtls_role = RTCDtlsRole::kUnknown;
Jonas Oreland149dc722019-08-28 06:10:273039 expected_rtcp_transport.selected_candidate_pair_changes = 0;
Philipp Hanckecc1b9b02022-05-04 16:58:263040 expected_rtcp_transport.ice_role = RTCIceRole::kUnknown;
Philipp Hancke95b1a342022-05-05 05:53:543041 expected_rtcp_transport.ice_local_username_fragment = "thelocalufrag";
Philipp Hancke1f491572022-05-09 15:43:313042 expected_rtcp_transport.ice_state = RTCIceTransportState::kChecking;
hbos0583b282016-11-30 09:50:143043
3044 expected_rtp_transport.rtcp_transport_stats_id = expected_rtcp_transport.id();
hbosdbb64d82016-12-21 09:57:463045 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
hbos0583b282016-11-30 09:50:143046 EXPECT_EQ(
3047 expected_rtp_transport,
3048 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
hbosdbb64d82016-12-21 09:57:463049 ASSERT_TRUE(report->Get(expected_rtcp_transport.id()));
hbos0583b282016-11-30 09:50:143050 EXPECT_EQ(
3051 expected_rtcp_transport,
3052 report->Get(expected_rtcp_transport.id())->cast_to<RTCTransportStats>());
hbos2fa7c672016-10-24 11:00:053053
hbos7064d592017-01-16 15:38:023054 // Get stats with an active connection (selected candidate pair).
Jonas Oreland149dc722019-08-28 06:10:273055 rtcp_transport_channel_stats.ice_transport_stats.connection_infos[0]
3056 .best_connection = true;
Steve Anton5b387312018-02-03 00:00:203057 pc_->SetTransportStats(kTransportName, {rtp_transport_channel_stats,
3058 rtcp_transport_channel_stats});
hbos2fa7c672016-10-24 11:00:053059
Steve Anton5b387312018-02-03 00:00:203060 report = stats_->GetFreshStatsReport();
hbos0583b282016-11-30 09:50:143061
hbos0583b282016-11-30 09:50:143062 expected_rtcp_transport.selected_candidate_pair_id =
Henrik Boström8dfc90f2022-09-02 07:39:293063 "CP" + rtcp_local_candidate->id() + "_" + rtcp_remote_candidate->id();
hbos0583b282016-11-30 09:50:143064
hbosdbb64d82016-12-21 09:57:463065 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
hbos0583b282016-11-30 09:50:143066 EXPECT_EQ(
3067 expected_rtp_transport,
3068 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
hbosdbb64d82016-12-21 09:57:463069 ASSERT_TRUE(report->Get(expected_rtcp_transport.id()));
hbos0583b282016-11-30 09:50:143070 EXPECT_EQ(
3071 expected_rtcp_transport,
3072 report->Get(expected_rtcp_transport.id())->cast_to<RTCTransportStats>());
hbos2fa7c672016-10-24 11:00:053073
3074 // Get stats with certificates.
3075 std::unique_ptr<CertificateInfo> local_certinfo =
Steve Anton5b387312018-02-03 00:00:203076 CreateFakeCertificateAndInfoFromDers({"(local) local", "(local) chain"});
3077 pc_->SetLocalCertificate(kTransportName, local_certinfo->certificate);
hbos2fa7c672016-10-24 11:00:053078 std::unique_ptr<CertificateInfo> remote_certinfo =
3079 CreateFakeCertificateAndInfoFromDers(
Steve Anton5b387312018-02-03 00:00:203080 {"(remote) local", "(remote) chain"});
Taylor Brandstetterc3928662018-02-23 21:04:513081 pc_->SetRemoteCertChain(
Benjamin Wright6c6c9df2018-10-25 08:16:263082 kTransportName,
3083 remote_certinfo->certificate->GetSSLCertificateChain().Clone());
hbos2fa7c672016-10-24 11:00:053084
Steve Anton5b387312018-02-03 00:00:203085 report = stats_->GetFreshStatsReport();
hbos0583b282016-11-30 09:50:143086
3087 expected_rtp_transport.local_certificate_id =
Henrik Boström8dfc90f2022-09-02 07:39:293088 "CF" + local_certinfo->fingerprints[0];
hbos0583b282016-11-30 09:50:143089 expected_rtp_transport.remote_certificate_id =
Henrik Boström8dfc90f2022-09-02 07:39:293090 "CF" + remote_certinfo->fingerprints[0];
hbos0583b282016-11-30 09:50:143091
3092 expected_rtcp_transport.local_certificate_id =
3093 *expected_rtp_transport.local_certificate_id;
3094 expected_rtcp_transport.remote_certificate_id =
3095 *expected_rtp_transport.remote_certificate_id;
3096
hbosdbb64d82016-12-21 09:57:463097 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
hbos0583b282016-11-30 09:50:143098 EXPECT_EQ(
3099 expected_rtp_transport,
3100 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
hbosdbb64d82016-12-21 09:57:463101 ASSERT_TRUE(report->Get(expected_rtcp_transport.id()));
hbos0583b282016-11-30 09:50:143102 EXPECT_EQ(
3103 expected_rtcp_transport,
3104 report->Get(expected_rtcp_transport.id())->cast_to<RTCTransportStats>());
hbos2fa7c672016-10-24 11:00:053105}
3106
Harald Alvestrand5cb78072019-10-28 08:51:173107TEST_F(RTCStatsCollectorTest, CollectRTCTransportStatsWithCrypto) {
3108 const char kTransportName[] = "transport";
3109
3110 pc_->AddVoiceChannel("audio", kTransportName);
3111
3112 std::unique_ptr<cricket::Candidate> rtp_local_candidate =
3113 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
3114 cricket::LOCAL_PORT_TYPE, 42);
3115 std::unique_ptr<cricket::Candidate> rtp_remote_candidate =
3116 CreateFakeCandidate("42.42.42.42", 42, "protocol",
3117 rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
3118 42);
3119 std::unique_ptr<cricket::Candidate> rtcp_local_candidate =
3120 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
3121 cricket::LOCAL_PORT_TYPE, 42);
3122 std::unique_ptr<cricket::Candidate> rtcp_remote_candidate =
3123 CreateFakeCandidate("42.42.42.42", 42, "protocol",
3124 rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
3125 42);
3126
3127 cricket::ConnectionInfo rtp_connection_info;
3128 rtp_connection_info.best_connection = false;
3129 rtp_connection_info.local_candidate = *rtp_local_candidate.get();
3130 rtp_connection_info.remote_candidate = *rtp_remote_candidate.get();
Harald Alvestrand5cb78072019-10-28 08:51:173131 cricket::TransportChannelStats rtp_transport_channel_stats;
3132 rtp_transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
3133 rtp_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
3134 rtp_connection_info);
3135 // The state must be connected in order for crypto parameters to show up.
Mirko Bonadei9f6808b2021-05-21 18:46:093136 rtp_transport_channel_stats.dtls_state = DtlsTransportState::kConnected;
Harald Alvestrand5cb78072019-10-28 08:51:173137 rtp_transport_channel_stats.ice_transport_stats
3138 .selected_candidate_pair_changes = 1;
3139 rtp_transport_channel_stats.ssl_version_bytes = 0x0203;
Philipp Hancke69c1df22022-04-22 13:46:243140 rtp_transport_channel_stats.dtls_role = rtc::SSL_CLIENT;
Philipp Hanckecc1b9b02022-05-04 16:58:263141 rtp_transport_channel_stats.ice_transport_stats.ice_role =
3142 cricket::ICEROLE_CONTROLLING;
Philipp Hancke95b1a342022-05-05 05:53:543143 rtp_transport_channel_stats.ice_transport_stats.ice_local_username_fragment =
3144 "thelocalufrag";
Philipp Hancke1f491572022-05-09 15:43:313145 rtp_transport_channel_stats.ice_transport_stats.ice_state =
3146 IceTransportState::kConnected;
Harald Alvestrand5cb78072019-10-28 08:51:173147 // 0x2F is TLS_RSA_WITH_AES_128_CBC_SHA according to IANA
3148 rtp_transport_channel_stats.ssl_cipher_suite = 0x2F;
Mirko Bonadei7750d802021-07-26 15:27:423149 rtp_transport_channel_stats.srtp_crypto_suite = rtc::kSrtpAes128CmSha1_80;
Harald Alvestrand5cb78072019-10-28 08:51:173150 pc_->SetTransportStats(kTransportName, {rtp_transport_channel_stats});
3151
3152 // Get stats
3153 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3154
3155 RTCTransportStats expected_rtp_transport(
Henrik Boström8dfc90f2022-09-02 07:39:293156 "Ttransport" + rtc::ToString(cricket::ICE_CANDIDATE_COMPONENT_RTP),
Harald Alvestrand5cb78072019-10-28 08:51:173157 report->timestamp_us());
Harald Alvestrand5cb78072019-10-28 08:51:173158 expected_rtp_transport.dtls_state = RTCDtlsTransportState::kConnected;
3159 expected_rtp_transport.selected_candidate_pair_changes = 1;
Philipp Hanckecc1b9b02022-05-04 16:58:263160 expected_rtp_transport.ice_role = RTCIceRole::kUnknown;
Jonas Oreland42da5a92022-03-01 12:55:373161 expected_rtp_transport.bytes_sent = 0;
3162 expected_rtp_transport.bytes_received = 0;
3163 expected_rtp_transport.packets_sent = 0;
3164 expected_rtp_transport.packets_received = 0;
Philipp Hancke95b1a342022-05-05 05:53:543165 expected_rtp_transport.ice_role = RTCIceRole::kControlling;
3166 expected_rtp_transport.ice_local_username_fragment = "thelocalufrag";
Philipp Hancke1f491572022-05-09 15:43:313167 expected_rtp_transport.ice_state = "connected";
Harald Alvestrand5cb78072019-10-28 08:51:173168 // Crypto parameters
3169 expected_rtp_transport.tls_version = "0203";
Philipp Hancke69c1df22022-04-22 13:46:243170 expected_rtp_transport.dtls_role = RTCDtlsRole::kClient;
Harald Alvestrand5cb78072019-10-28 08:51:173171 expected_rtp_transport.dtls_cipher = "TLS_RSA_WITH_AES_128_CBC_SHA";
3172 expected_rtp_transport.srtp_cipher = "AES_CM_128_HMAC_SHA1_80";
3173
3174 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
3175 EXPECT_EQ(
3176 expected_rtp_transport,
3177 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
3178}
3179
Harald Alvestrand89061872018-01-02 13:08:343180TEST_F(RTCStatsCollectorTest, CollectNoStreamRTCOutboundRTPStreamStats_Audio) {
Harald Alvestrand89061872018-01-02 13:08:343181 cricket::VoiceMediaInfo voice_media_info;
3182
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 = 1;
3186 voice_media_info.senders[0].packets_sent = 2;
Henrik Boströmaebba7b2022-10-26 14:53:033187 voice_media_info.senders[0].total_packet_send_delay = TimeDelta::Seconds(0.5);
Henrik Boströmcf96e0f2019-04-17 11:51:533188 voice_media_info.senders[0].retransmitted_packets_sent = 20;
Niels Möllerac0a4cb2019-10-09 13:01:333189 voice_media_info.senders[0].payload_bytes_sent = 3;
3190 voice_media_info.senders[0].header_and_padding_bytes_sent = 4;
Henrik Boströmcf96e0f2019-04-17 11:51:533191 voice_media_info.senders[0].retransmitted_bytes_sent = 30;
Jakob Ivarssone91c9922021-07-06 07:55:433192 voice_media_info.senders[0].nacks_rcvd = 31;
Harald Alvestrand89061872018-01-02 13:08:343193 voice_media_info.senders[0].codec_payload_type = 42;
Philipp Hancke684e2412022-07-28 10:41:003194 voice_media_info.senders[0].active = true;
Harald Alvestrand89061872018-01-02 13:08:343195
3196 RtpCodecParameters codec_parameters;
3197 codec_parameters.payload_type = 42;
3198 codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
3199 codec_parameters.name = "dummy";
3200 codec_parameters.clock_rate = 0;
3201 voice_media_info.send_codecs.insert(
3202 std::make_pair(codec_parameters.payload_type, codec_parameters));
3203
Steve Anton5b387312018-02-03 00:00:203204 // Emulates the case where AddTrack is used without an associated MediaStream
Tommi19015512022-02-02 10:49:353205 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Steve Anton5b387312018-02-03 00:00:203206 stats_->SetupLocalTrackAndSender(cricket::MEDIA_TYPE_AUDIO,
Henrik Boström646fda02019-05-22 13:49:423207 "LocalAudioTrackID", 1, false,
3208 /*attachment_id=*/50);
Harald Alvestrand89061872018-01-02 13:08:343209
Steve Anton5b387312018-02-03 00:00:203210 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Harald Alvestrand89061872018-01-02 13:08:343211
Henrik Boströmb43e3bb2022-09-26 10:36:443212 RTCOutboundRTPStreamStats expected_audio("OTTransportName1A1",
3213 report->timestamp_us());
Henrik Boström8dfc90f2022-09-02 07:39:293214 expected_audio.media_source_id = "SA50";
Henrik Boström1ab61882022-06-16 15:07:333215 expected_audio.mid = "AudioMid";
Harald Alvestrand89061872018-01-02 13:08:343216 expected_audio.ssrc = 1;
Harald Alvestrand89061872018-01-02 13:08:343217 expected_audio.media_type = "audio";
Philipp Hancke3bc01662018-08-28 12:55:033218 expected_audio.kind = "audio";
Henrik Boström15166b22022-10-19 09:06:583219 expected_audio.track_id =
3220 IdForType<DEPRECATED_RTCMediaStreamTrackStats>(report.get());
Henrik Boström8dfc90f2022-09-02 07:39:293221 expected_audio.transport_id = "TTransportName1";
3222 expected_audio.codec_id = "COTTransportName1_42";
Harald Alvestrand89061872018-01-02 13:08:343223 expected_audio.packets_sent = 2;
Henrik Boströmaebba7b2022-10-26 14:53:033224 expected_audio.total_packet_send_delay = 0.5;
Henrik Boströmcf96e0f2019-04-17 11:51:533225 expected_audio.retransmitted_packets_sent = 20;
Harald Alvestrand89061872018-01-02 13:08:343226 expected_audio.bytes_sent = 3;
Niels Möllerac0a4cb2019-10-09 13:01:333227 expected_audio.header_bytes_sent = 4;
Henrik Boströmcf96e0f2019-04-17 11:51:533228 expected_audio.retransmitted_bytes_sent = 30;
Jakob Ivarssone91c9922021-07-06 07:55:433229 expected_audio.nack_count = 31;
Philipp Hancke684e2412022-07-28 10:41:003230 expected_audio.active = true;
Harald Alvestrand89061872018-01-02 13:08:343231
3232 ASSERT_TRUE(report->Get(expected_audio.id()));
3233 EXPECT_EQ(
3234 report->Get(expected_audio.id())->cast_to<RTCOutboundRTPStreamStats>(),
3235 expected_audio);
Harald Alvestrand89061872018-01-02 13:08:343236 EXPECT_TRUE(report->Get(*expected_audio.track_id));
3237 EXPECT_TRUE(report->Get(*expected_audio.transport_id));
3238 EXPECT_TRUE(report->Get(*expected_audio.codec_id));
3239}
3240
Henrik Boström646fda02019-05-22 13:49:423241TEST_F(RTCStatsCollectorTest, RTCAudioSourceStatsCollectedForSenderWithTrack) {
3242 const uint32_t kSsrc = 4;
3243 const int kAttachmentId = 42;
3244
3245 cricket::VoiceMediaInfo voice_media_info;
3246 voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
3247 voice_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3248 voice_media_info.senders[0].local_stats[0].ssrc = kSsrc;
Henrik Boströmd2c336f2019-07-03 15:11:103249 voice_media_info.senders[0].audio_level = 32767; // [0,32767]
3250 voice_media_info.senders[0].total_input_energy = 2.0;
3251 voice_media_info.senders[0].total_input_duration = 3.0;
Taylor Brandstetter64851c02021-06-24 20:32:503252 voice_media_info.senders[0].apm_statistics.echo_return_loss = 42.0;
3253 voice_media_info.senders[0].apm_statistics.echo_return_loss_enhancement =
3254 52.0;
Tommi19015512022-02-02 10:49:353255 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Henrik Boström646fda02019-05-22 13:49:423256 stats_->SetupLocalTrackAndSender(cricket::MEDIA_TYPE_AUDIO,
3257 "LocalAudioTrackID", kSsrc, false,
3258 kAttachmentId);
3259
3260 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3261
Henrik Boström8dfc90f2022-09-02 07:39:293262 RTCAudioSourceStats expected_audio("SA42", report->timestamp_us());
Henrik Boström646fda02019-05-22 13:49:423263 expected_audio.track_identifier = "LocalAudioTrackID";
3264 expected_audio.kind = "audio";
Henrik Boströmd2c336f2019-07-03 15:11:103265 expected_audio.audio_level = 1.0; // [0,1]
3266 expected_audio.total_audio_energy = 2.0;
3267 expected_audio.total_samples_duration = 3.0;
Taylor Brandstetter64851c02021-06-24 20:32:503268 expected_audio.echo_return_loss = 42.0;
3269 expected_audio.echo_return_loss_enhancement = 52.0;
Henrik Boström646fda02019-05-22 13:49:423270
3271 ASSERT_TRUE(report->Get(expected_audio.id()));
3272 EXPECT_EQ(report->Get(expected_audio.id())->cast_to<RTCAudioSourceStats>(),
3273 expected_audio);
3274}
3275
3276TEST_F(RTCStatsCollectorTest, RTCVideoSourceStatsCollectedForSenderWithTrack) {
3277 const uint32_t kSsrc = 4;
3278 const int kAttachmentId = 42;
3279 const int kVideoSourceWidth = 12;
3280 const int kVideoSourceHeight = 34;
3281
3282 cricket::VideoMediaInfo video_media_info;
Henrik Boströma0ff50c2020-05-05 13:54:463283 video_media_info.aggregated_senders.push_back(cricket::VideoSenderInfo());
Henrik Boström646fda02019-05-22 13:49:423284 video_media_info.senders.push_back(cricket::VideoSenderInfo());
3285 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3286 video_media_info.senders[0].local_stats[0].ssrc = kSsrc;
Byoungchan Leeefe46b62021-11-10 02:23:563287 video_media_info.senders[0].framerate_input = 29.0;
Henrik Boströma0ff50c2020-05-05 13:54:463288 video_media_info.aggregated_senders[0].local_stats.push_back(
3289 cricket::SsrcSenderInfo());
3290 video_media_info.aggregated_senders[0].local_stats[0].ssrc = kSsrc;
Byoungchan Leeefe46b62021-11-10 02:23:563291 video_media_info.aggregated_senders[0].framerate_input = 29.0;
Di Wu668dbf62021-02-27 08:29:153292 video_media_info.aggregated_senders[0].frames = 10001;
Tommi19015512022-02-02 10:49:353293 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström646fda02019-05-22 13:49:423294
3295 auto video_source = FakeVideoTrackSourceForStats::Create(kVideoSourceWidth,
3296 kVideoSourceHeight);
3297 auto video_track = FakeVideoTrackForStats::Create(
3298 "LocalVideoTrackID", MediaStreamTrackInterface::kLive, video_source);
3299 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
3300 cricket::MEDIA_TYPE_VIDEO, video_track, kSsrc, kAttachmentId, {});
Tommi6589def2022-02-17 22:36:473301 EXPECT_CALL(*sender, Stop());
3302 EXPECT_CALL(*sender, SetMediaChannel(_));
Henrik Boström646fda02019-05-22 13:49:423303 pc_->AddSender(sender);
3304
3305 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3306
Henrik Boström8dfc90f2022-09-02 07:39:293307 RTCVideoSourceStats expected_video("SV42", report->timestamp_us());
Henrik Boström646fda02019-05-22 13:49:423308 expected_video.track_identifier = "LocalVideoTrackID";
3309 expected_video.kind = "video";
3310 expected_video.width = kVideoSourceWidth;
3311 expected_video.height = kVideoSourceHeight;
Byoungchan Leeefe46b62021-11-10 02:23:563312 expected_video.frames_per_second = 29.0;
Di Wu668dbf62021-02-27 08:29:153313 expected_video.frames = 10001;
Henrik Boström646fda02019-05-22 13:49:423314
3315 ASSERT_TRUE(report->Get(expected_video.id()));
3316 EXPECT_EQ(report->Get(expected_video.id())->cast_to<RTCVideoSourceStats>(),
3317 expected_video);
3318}
3319
3320// This test exercises the current behavior and code path, but the correct
3321// behavior is to report frame rate even if we have no SSRC.
3322// TODO(hbos): When we know the frame rate even if we have no SSRC, update the
3323// expectations of this test.
3324TEST_F(RTCStatsCollectorTest,
3325 RTCVideoSourceStatsMissingFrameRateWhenSenderHasNoSsrc) {
3326 // TODO(https://crbug.com/webrtc/8694): When 0 is no longer a magic value for
3327 // "none", update this test.
3328 const uint32_t kNoSsrc = 0;
3329 const int kAttachmentId = 42;
3330 const int kVideoSourceWidth = 12;
3331 const int kVideoSourceHeight = 34;
3332
3333 cricket::VideoMediaInfo video_media_info;
3334 video_media_info.senders.push_back(cricket::VideoSenderInfo());
3335 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
Byoungchan Leeefe46b62021-11-10 02:23:563336 video_media_info.senders[0].framerate_input = 29.0;
Tommi19015512022-02-02 10:49:353337 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström646fda02019-05-22 13:49:423338
3339 auto video_source = FakeVideoTrackSourceForStats::Create(kVideoSourceWidth,
3340 kVideoSourceHeight);
3341 auto video_track = FakeVideoTrackForStats::Create(
3342 "LocalVideoTrackID", MediaStreamTrackInterface::kLive, video_source);
3343 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
3344 cricket::MEDIA_TYPE_VIDEO, video_track, kNoSsrc, kAttachmentId, {});
Tommi6589def2022-02-17 22:36:473345 EXPECT_CALL(*sender, Stop());
3346 EXPECT_CALL(*sender, SetMediaChannel(_));
Henrik Boström646fda02019-05-22 13:49:423347 pc_->AddSender(sender);
3348
3349 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Henrik Boström8dfc90f2022-09-02 07:39:293350 ASSERT_TRUE(report->Get("SV42"));
3351 auto video_stats = report->Get("SV42")->cast_to<RTCVideoSourceStats>();
Henrik Boström646fda02019-05-22 13:49:423352 EXPECT_FALSE(video_stats.frames_per_second.is_defined());
Di Wu668dbf62021-02-27 08:29:153353 EXPECT_FALSE(video_stats.frames.is_defined());
Henrik Boström646fda02019-05-22 13:49:423354}
3355
3356// The track not having a source is not expected to be true in practise, but
3357// this is true in some tests relying on fakes. This test covers that code path.
3358TEST_F(RTCStatsCollectorTest,
3359 RTCVideoSourceStatsMissingResolutionWhenTrackHasNoSource) {
3360 const uint32_t kSsrc = 4;
3361 const int kAttachmentId = 42;
3362
3363 cricket::VideoMediaInfo video_media_info;
3364 video_media_info.senders.push_back(cricket::VideoSenderInfo());
3365 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3366 video_media_info.senders[0].local_stats[0].ssrc = kSsrc;
Byoungchan Leeefe46b62021-11-10 02:23:563367 video_media_info.senders[0].framerate_input = 29.0;
Tommi19015512022-02-02 10:49:353368 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström646fda02019-05-22 13:49:423369
3370 auto video_track = FakeVideoTrackForStats::Create(
3371 "LocalVideoTrackID", MediaStreamTrackInterface::kLive,
3372 /*source=*/nullptr);
3373 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
3374 cricket::MEDIA_TYPE_VIDEO, video_track, kSsrc, kAttachmentId, {});
Tommi6589def2022-02-17 22:36:473375 EXPECT_CALL(*sender, Stop());
3376 EXPECT_CALL(*sender, SetMediaChannel(_));
Henrik Boström646fda02019-05-22 13:49:423377 pc_->AddSender(sender);
3378
3379 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Henrik Boström8dfc90f2022-09-02 07:39:293380 ASSERT_TRUE(report->Get("SV42"));
3381 auto video_stats = report->Get("SV42")->cast_to<RTCVideoSourceStats>();
Henrik Boström646fda02019-05-22 13:49:423382 EXPECT_FALSE(video_stats.width.is_defined());
3383 EXPECT_FALSE(video_stats.height.is_defined());
3384}
3385
3386TEST_F(RTCStatsCollectorTest,
3387 RTCAudioSourceStatsNotCollectedForSenderWithoutTrack) {
3388 const uint32_t kSsrc = 4;
3389 const int kAttachmentId = 42;
3390
3391 cricket::VoiceMediaInfo voice_media_info;
3392 voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
3393 voice_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3394 voice_media_info.senders[0].local_stats[0].ssrc = kSsrc;
Tommi19015512022-02-02 10:49:353395 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Henrik Boström646fda02019-05-22 13:49:423396 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
3397 cricket::MEDIA_TYPE_AUDIO, /*track=*/nullptr, kSsrc, kAttachmentId, {});
Tommi6589def2022-02-17 22:36:473398 EXPECT_CALL(*sender, Stop());
3399 EXPECT_CALL(*sender, SetMediaChannel(_));
Henrik Boström646fda02019-05-22 13:49:423400 pc_->AddSender(sender);
3401
3402 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Henrik Boström8dfc90f2022-09-02 07:39:293403 EXPECT_FALSE(report->Get("SA42"));
Henrik Boström646fda02019-05-22 13:49:423404}
3405
Henrik Boström883eefc2019-05-27 11:40:253406// Parameterized tests on cricket::MediaType (audio or video).
3407class RTCStatsCollectorTestWithParamKind
3408 : public RTCStatsCollectorTest,
3409 public ::testing::WithParamInterface<cricket::MediaType> {
3410 public:
3411 RTCStatsCollectorTestWithParamKind() : media_type_(GetParam()) {
3412 RTC_DCHECK(media_type_ == cricket::MEDIA_TYPE_AUDIO ||
3413 media_type_ == cricket::MEDIA_TYPE_VIDEO);
3414 }
3415
Henrik Boström8dfc90f2022-09-02 07:39:293416 std::string MediaTypeCharStr() const {
Henrik Boström883eefc2019-05-27 11:40:253417 switch (media_type_) {
3418 case cricket::MEDIA_TYPE_AUDIO:
Henrik Boström8dfc90f2022-09-02 07:39:293419 return "A";
Henrik Boström883eefc2019-05-27 11:40:253420 case cricket::MEDIA_TYPE_VIDEO:
Henrik Boström8dfc90f2022-09-02 07:39:293421 return "V";
3422 case cricket::MEDIA_TYPE_DATA:
3423 case cricket::MEDIA_TYPE_UNSUPPORTED:
3424 RTC_DCHECK_NOTREACHED();
3425 return "?";
3426 }
3427 }
3428
3429 std::string MediaTypeKind() const {
3430 switch (media_type_) {
3431 case cricket::MEDIA_TYPE_AUDIO:
3432 return "audio";
3433 case cricket::MEDIA_TYPE_VIDEO:
3434 return "video";
Henrik Boström883eefc2019-05-27 11:40:253435 case cricket::MEDIA_TYPE_DATA:
Philipp Hancke4e8c1152020-10-13 10:43:153436 case cricket::MEDIA_TYPE_UNSUPPORTED:
Artem Titovd3251962021-11-15 15:57:073437 RTC_DCHECK_NOTREACHED();
Henrik Boström883eefc2019-05-27 11:40:253438 return "";
3439 }
3440 }
3441
Henrik Boström883eefc2019-05-27 11:40:253442 // Adds a sender and channel of the appropriate kind, creating a sender info
Artem Titov880fa812021-07-30 20:30:233443 // with the report block's `source_ssrc` and report block data.
Eldar Relloc07e9042020-07-03 08:08:073444 void AddSenderInfoAndMediaChannel(
3445 std::string transport_name,
3446 const std::vector<ReportBlockData>& report_block_datas,
3447 absl::optional<RtpCodecParameters> codec) {
Henrik Boström883eefc2019-05-27 11:40:253448 switch (media_type_) {
3449 case cricket::MEDIA_TYPE_AUDIO: {
3450 cricket::VoiceMediaInfo voice_media_info;
Eldar Relloc07e9042020-07-03 08:08:073451 for (const auto& report_block_data : report_block_datas) {
3452 cricket::VoiceSenderInfo sender;
3453 sender.local_stats.push_back(cricket::SsrcSenderInfo());
3454 sender.local_stats[0].ssrc =
3455 report_block_data.report_block().source_ssrc;
3456 if (codec.has_value()) {
3457 sender.codec_payload_type = codec->payload_type;
3458 voice_media_info.send_codecs.insert(
3459 std::make_pair(codec->payload_type, *codec));
3460 }
3461 sender.report_block_datas.push_back(report_block_data);
3462 voice_media_info.senders.push_back(sender);
Henrik Boström883eefc2019-05-27 11:40:253463 }
Tommi19015512022-02-02 10:49:353464 pc_->AddVoiceChannel("mid", transport_name, voice_media_info);
Henrik Boström883eefc2019-05-27 11:40:253465 return;
3466 }
3467 case cricket::MEDIA_TYPE_VIDEO: {
3468 cricket::VideoMediaInfo video_media_info;
Eldar Relloc07e9042020-07-03 08:08:073469 for (const auto& report_block_data : report_block_datas) {
3470 cricket::VideoSenderInfo sender;
3471 sender.local_stats.push_back(cricket::SsrcSenderInfo());
3472 sender.local_stats[0].ssrc =
3473 report_block_data.report_block().source_ssrc;
3474 if (codec.has_value()) {
3475 sender.codec_payload_type = codec->payload_type;
3476 video_media_info.send_codecs.insert(
3477 std::make_pair(codec->payload_type, *codec));
3478 }
3479 sender.report_block_datas.push_back(report_block_data);
3480 video_media_info.aggregated_senders.push_back(sender);
3481 video_media_info.senders.push_back(sender);
Henrik Boström883eefc2019-05-27 11:40:253482 }
Tommi19015512022-02-02 10:49:353483 pc_->AddVideoChannel("mid", transport_name, video_media_info);
Henrik Boström883eefc2019-05-27 11:40:253484 return;
3485 }
3486 case cricket::MEDIA_TYPE_DATA:
Philipp Hancke4e8c1152020-10-13 10:43:153487 case cricket::MEDIA_TYPE_UNSUPPORTED:
Artem Titovd3251962021-11-15 15:57:073488 RTC_DCHECK_NOTREACHED();
Henrik Boström883eefc2019-05-27 11:40:253489 }
3490 }
3491
3492 protected:
3493 cricket::MediaType media_type_;
3494};
3495
3496// Verifies RTCRemoteInboundRtpStreamStats members that don't require
3497// RTCCodecStats (codecId, jitter) and without setting up an RTCP transport.
3498TEST_P(RTCStatsCollectorTestWithParamKind,
3499 RTCRemoteInboundRtpStreamStatsCollectedFromReportBlock) {
3500 const int64_t kReportBlockTimestampUtcUs = 123456789;
Di Wu86f04ad2021-03-01 07:36:033501 const uint8_t kFractionLost = 12;
Di Wu88a51b22021-03-01 19:22:063502 const int64_t kRoundTripTimeSample1Ms = 1234;
3503 const double kRoundTripTimeSample1Seconds = 1.234;
3504 const int64_t kRoundTripTimeSample2Ms = 13000;
3505 const double kRoundTripTimeSample2Seconds = 13;
Henrik Boström883eefc2019-05-27 11:40:253506
3507 // The report block's timestamp cannot be from the future, set the fake clock
3508 // to match.
Danil Chapovalov0c626af2020-02-10 10:16:003509 fake_clock_.SetTime(Timestamp::Micros(kReportBlockTimestampUtcUs));
Eldar Relloc07e9042020-07-03 08:08:073510 auto ssrcs = {12, 13};
3511 std::vector<ReportBlockData> report_block_datas;
3512 for (auto ssrc : ssrcs) {
3513 RTCPReportBlock report_block;
3514 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
Artem Titov880fa812021-07-30 20:30:233515 // `source_ssrc`, "SSRC of the RTP packet sender".
Eldar Relloc07e9042020-07-03 08:08:073516 report_block.source_ssrc = ssrc;
3517 report_block.packets_lost = 7;
Di Wu86f04ad2021-03-01 07:36:033518 report_block.fraction_lost = kFractionLost;
Eldar Relloc07e9042020-07-03 08:08:073519 ReportBlockData report_block_data;
3520 report_block_data.SetReportBlock(report_block, kReportBlockTimestampUtcUs);
Di Wu88a51b22021-03-01 19:22:063521 report_block_data.AddRoundTripTimeSample(kRoundTripTimeSample1Ms);
Eldar Relloc07e9042020-07-03 08:08:073522 // Only the last sample should be exposed as the
Artem Titovcfea2182021-08-09 23:22:313523 // `RTCRemoteInboundRtpStreamStats::round_trip_time`.
Di Wu88a51b22021-03-01 19:22:063524 report_block_data.AddRoundTripTimeSample(kRoundTripTimeSample2Ms);
Eldar Relloc07e9042020-07-03 08:08:073525 report_block_datas.push_back(report_block_data);
3526 }
3527 AddSenderInfoAndMediaChannel("TransportName", report_block_datas,
Henrik Boström883eefc2019-05-27 11:40:253528 absl::nullopt);
3529
3530 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Eldar Relloc07e9042020-07-03 08:08:073531 for (auto ssrc : ssrcs) {
Henrik Boström8dfc90f2022-09-02 07:39:293532 std::string stream_id = "" + std::to_string(ssrc);
Eldar Relloc07e9042020-07-03 08:08:073533 RTCRemoteInboundRtpStreamStats expected_remote_inbound_rtp(
Henrik Boström8dfc90f2022-09-02 07:39:293534 "RI" + MediaTypeCharStr() + stream_id, kReportBlockTimestampUtcUs);
Eldar Relloc07e9042020-07-03 08:08:073535 expected_remote_inbound_rtp.ssrc = ssrc;
Di Wu86f04ad2021-03-01 07:36:033536 expected_remote_inbound_rtp.fraction_lost =
3537 static_cast<double>(kFractionLost) / (1 << 8);
Henrik Boström8dfc90f2022-09-02 07:39:293538 expected_remote_inbound_rtp.kind = MediaTypeKind();
Eldar Relloc07e9042020-07-03 08:08:073539 expected_remote_inbound_rtp.transport_id =
Henrik Boström8dfc90f2022-09-02 07:39:293540 "TTransportName1"; // 1 for RTP (we have no RTCP
3541 // transport)
Eldar Relloc07e9042020-07-03 08:08:073542 expected_remote_inbound_rtp.packets_lost = 7;
Henrik Boströmb43e3bb2022-09-26 10:36:443543 expected_remote_inbound_rtp.local_id =
3544 "OTTransportName1" + MediaTypeCharStr() + stream_id;
Di Wu88a51b22021-03-01 19:22:063545 expected_remote_inbound_rtp.round_trip_time = kRoundTripTimeSample2Seconds;
3546 expected_remote_inbound_rtp.total_round_trip_time =
3547 kRoundTripTimeSample1Seconds + kRoundTripTimeSample2Seconds;
3548 expected_remote_inbound_rtp.round_trip_time_measurements = 2;
Artem Titov880fa812021-07-30 20:30:233549 // This test does not set up RTCCodecStats, so `codec_id` and `jitter` are
Eldar Relloc07e9042020-07-03 08:08:073550 // expected to be missing. These are tested separately.
Henrik Boström883eefc2019-05-27 11:40:253551
Eldar Relloc07e9042020-07-03 08:08:073552 ASSERT_TRUE(report->Get(expected_remote_inbound_rtp.id()));
3553 EXPECT_EQ(report->Get(expected_remote_inbound_rtp.id())
3554 ->cast_to<RTCRemoteInboundRtpStreamStats>(),
3555 expected_remote_inbound_rtp);
3556 EXPECT_TRUE(report->Get(*expected_remote_inbound_rtp.transport_id));
3557 ASSERT_TRUE(report->Get(*expected_remote_inbound_rtp.local_id));
3558 // Lookup works in both directions.
3559 EXPECT_EQ(*report->Get(*expected_remote_inbound_rtp.local_id)
3560 ->cast_to<RTCOutboundRTPStreamStats>()
3561 .remote_id,
3562 expected_remote_inbound_rtp.id());
3563 }
Henrik Boström883eefc2019-05-27 11:40:253564}
3565
3566TEST_P(RTCStatsCollectorTestWithParamKind,
Henrik Boströma3a3b6d2022-11-22 08:56:493567 RTCRemoteInboundRtpStreamStatsRttMissingBeforeMeasurement) {
3568 constexpr int64_t kReportBlockTimestampUtcUs = 123456789;
3569
3570 RTCPReportBlock report_block;
3571 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
3572 // `source_ssrc`, "SSRC of the RTP packet sender".
3573 report_block.source_ssrc = 12;
3574 ReportBlockData report_block_data; // AddRoundTripTimeSample() not called.
3575 report_block_data.SetReportBlock(report_block, kReportBlockTimestampUtcUs);
3576
3577 AddSenderInfoAndMediaChannel("TransportName", {report_block_data},
3578 absl::nullopt);
3579
3580 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3581
3582 std::string remote_inbound_rtp_id = "RI" + MediaTypeCharStr() + "12";
3583 ASSERT_TRUE(report->Get(remote_inbound_rtp_id));
3584 auto& remote_inbound_rtp = report->Get(remote_inbound_rtp_id)
3585 ->cast_to<RTCRemoteInboundRtpStreamStats>();
3586
3587 EXPECT_TRUE(remote_inbound_rtp.round_trip_time_measurements.is_defined());
3588 EXPECT_EQ(0, *remote_inbound_rtp.round_trip_time_measurements);
3589 EXPECT_FALSE(remote_inbound_rtp.round_trip_time.is_defined());
3590}
3591
3592TEST_P(RTCStatsCollectorTestWithParamKind,
Henrik Boström883eefc2019-05-27 11:40:253593 RTCRemoteInboundRtpStreamStatsWithTimestampFromReportBlock) {
3594 const int64_t kReportBlockTimestampUtcUs = 123456789;
Danil Chapovalov0c626af2020-02-10 10:16:003595 fake_clock_.SetTime(Timestamp::Micros(kReportBlockTimestampUtcUs));
Henrik Boström883eefc2019-05-27 11:40:253596
3597 RTCPReportBlock report_block;
Henrik Boström8605fbf2019-06-24 14:44:513598 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
Artem Titov880fa812021-07-30 20:30:233599 // `source_ssrc`, "SSRC of the RTP packet sender".
Henrik Boström883eefc2019-05-27 11:40:253600 report_block.source_ssrc = 12;
3601 ReportBlockData report_block_data;
3602 report_block_data.SetReportBlock(report_block, kReportBlockTimestampUtcUs);
3603
Eldar Relloc07e9042020-07-03 08:08:073604 AddSenderInfoAndMediaChannel("TransportName", {report_block_data},
Henrik Boström883eefc2019-05-27 11:40:253605 absl::nullopt);
3606
3607 // Advance time, it should be OK to have fresher reports than report blocks.
Danil Chapovalov0c626af2020-02-10 10:16:003608 fake_clock_.AdvanceTime(TimeDelta::Micros(1234));
Henrik Boström883eefc2019-05-27 11:40:253609
3610 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3611
Henrik Boström8dfc90f2022-09-02 07:39:293612 std::string remote_inbound_rtp_id = "RI" + MediaTypeCharStr() + "12";
Henrik Boström883eefc2019-05-27 11:40:253613 ASSERT_TRUE(report->Get(remote_inbound_rtp_id));
3614 auto& remote_inbound_rtp = report->Get(remote_inbound_rtp_id)
3615 ->cast_to<RTCRemoteInboundRtpStreamStats>();
3616
3617 // Even though the report time is different, the remote-inbound-rtp timestamp
3618 // is of the time that the report block was received.
3619 EXPECT_EQ(kReportBlockTimestampUtcUs + 1234, report->timestamp_us());
3620 EXPECT_EQ(kReportBlockTimestampUtcUs, remote_inbound_rtp.timestamp_us());
3621}
3622
3623TEST_P(RTCStatsCollectorTestWithParamKind,
3624 RTCRemoteInboundRtpStreamStatsWithCodecBasedMembers) {
3625 const int64_t kReportBlockTimestampUtcUs = 123456789;
Danil Chapovalov0c626af2020-02-10 10:16:003626 fake_clock_.SetTime(Timestamp::Micros(kReportBlockTimestampUtcUs));
Henrik Boström883eefc2019-05-27 11:40:253627
3628 RTCPReportBlock report_block;
Henrik Boström8605fbf2019-06-24 14:44:513629 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
Artem Titov880fa812021-07-30 20:30:233630 // `source_ssrc`, "SSRC of the RTP packet sender".
Henrik Boström883eefc2019-05-27 11:40:253631 report_block.source_ssrc = 12;
3632 report_block.jitter = 5000;
3633 ReportBlockData report_block_data;
3634 report_block_data.SetReportBlock(report_block, kReportBlockTimestampUtcUs);
3635
3636 RtpCodecParameters codec;
3637 codec.payload_type = 3;
3638 codec.kind = media_type_;
3639 codec.clock_rate = 1000;
3640
Eldar Relloc07e9042020-07-03 08:08:073641 AddSenderInfoAndMediaChannel("TransportName", {report_block_data}, codec);
Henrik Boström883eefc2019-05-27 11:40:253642
3643 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3644
Henrik Boström8dfc90f2022-09-02 07:39:293645 std::string remote_inbound_rtp_id = "RI" + MediaTypeCharStr() + "12";
Henrik Boström883eefc2019-05-27 11:40:253646 ASSERT_TRUE(report->Get(remote_inbound_rtp_id));
3647 auto& remote_inbound_rtp = report->Get(remote_inbound_rtp_id)
3648 ->cast_to<RTCRemoteInboundRtpStreamStats>();
3649
3650 EXPECT_TRUE(remote_inbound_rtp.codec_id.is_defined());
3651 EXPECT_TRUE(report->Get(*remote_inbound_rtp.codec_id));
3652
3653 EXPECT_TRUE(remote_inbound_rtp.jitter.is_defined());
3654 // The jitter (in seconds) is the report block's jitter divided by the codec's
3655 // clock rate.
3656 EXPECT_EQ(5.0, *remote_inbound_rtp.jitter);
3657}
3658
3659TEST_P(RTCStatsCollectorTestWithParamKind,
3660 RTCRemoteInboundRtpStreamStatsWithRtcpTransport) {
3661 const int64_t kReportBlockTimestampUtcUs = 123456789;
Danil Chapovalov0c626af2020-02-10 10:16:003662 fake_clock_.SetTime(Timestamp::Micros(kReportBlockTimestampUtcUs));
Henrik Boström883eefc2019-05-27 11:40:253663
3664 RTCPReportBlock report_block;
Henrik Boström8605fbf2019-06-24 14:44:513665 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
Artem Titov880fa812021-07-30 20:30:233666 // `source_ssrc`, "SSRC of the RTP packet sender".
Henrik Boström883eefc2019-05-27 11:40:253667 report_block.source_ssrc = 12;
3668 ReportBlockData report_block_data;
3669 report_block_data.SetReportBlock(report_block, kReportBlockTimestampUtcUs);
3670
3671 cricket::TransportChannelStats rtp_transport_channel_stats;
3672 rtp_transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
Mirko Bonadei9f6808b2021-05-21 18:46:093673 rtp_transport_channel_stats.dtls_state = DtlsTransportState::kNew;
Henrik Boström883eefc2019-05-27 11:40:253674 cricket::TransportChannelStats rtcp_transport_channel_stats;
3675 rtcp_transport_channel_stats.component =
3676 cricket::ICE_CANDIDATE_COMPONENT_RTCP;
Mirko Bonadei9f6808b2021-05-21 18:46:093677 rtcp_transport_channel_stats.dtls_state = DtlsTransportState::kNew;
Henrik Boström883eefc2019-05-27 11:40:253678 pc_->SetTransportStats("TransportName", {rtp_transport_channel_stats,
3679 rtcp_transport_channel_stats});
Eldar Relloc07e9042020-07-03 08:08:073680 AddSenderInfoAndMediaChannel("TransportName", {report_block_data},
Henrik Boström883eefc2019-05-27 11:40:253681 absl::nullopt);
3682
3683 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3684
Henrik Boström8dfc90f2022-09-02 07:39:293685 std::string remote_inbound_rtp_id = "RI" + MediaTypeCharStr() + "12";
Henrik Boström883eefc2019-05-27 11:40:253686 ASSERT_TRUE(report->Get(remote_inbound_rtp_id));
3687 auto& remote_inbound_rtp = report->Get(remote_inbound_rtp_id)
3688 ->cast_to<RTCRemoteInboundRtpStreamStats>();
3689
3690 EXPECT_TRUE(remote_inbound_rtp.transport_id.is_defined());
Henrik Boström8dfc90f2022-09-02 07:39:293691 EXPECT_EQ("TTransportName2", // 2 for RTCP
Henrik Boström883eefc2019-05-27 11:40:253692 *remote_inbound_rtp.transport_id);
3693 EXPECT_TRUE(report->Get(*remote_inbound_rtp.transport_id));
3694}
3695
Mirko Bonadei1b575412019-09-23 06:34:503696INSTANTIATE_TEST_SUITE_P(All,
Henrik Boström883eefc2019-05-27 11:40:253697 RTCStatsCollectorTestWithParamKind,
3698 ::testing::Values(cricket::MEDIA_TYPE_AUDIO, // "/0"
3699 cricket::MEDIA_TYPE_VIDEO)); // "/1"
3700
Alessio Bazzicaf7b1b952021-03-23 16:23:043701// Checks that no remote outbound stats are collected if not available in
3702// `VoiceMediaInfo`.
3703TEST_F(RTCStatsCollectorTest,
3704 RTCRemoteOutboundRtpAudioStreamStatsNotCollected) {
3705 ExampleStatsGraph graph =
3706 SetupExampleStatsVoiceGraph(/*add_remote_outbound_stats=*/false);
3707 EXPECT_FALSE(graph.full_report->Get(graph.remote_outbound_rtp_id));
3708 // Also check that no other remote outbound report is created (in case the
3709 // expected ID is incorrect).
3710 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3711 ASSERT_NE(report->begin(), report->end())
3712 << "No reports have been generated.";
3713 for (const auto& stats : *report) {
3714 SCOPED_TRACE(stats.id());
3715 EXPECT_NE(stats.type(), RTCRemoteOutboundRtpStreamStats::kType);
3716 }
3717}
3718
3719// Checks that the remote outbound stats are collected when available in
3720// `VoiceMediaInfo`.
3721TEST_F(RTCStatsCollectorTest, RTCRemoteOutboundRtpAudioStreamStatsCollected) {
3722 ExampleStatsGraph graph =
3723 SetupExampleStatsVoiceGraph(/*add_remote_outbound_stats=*/true);
3724 ASSERT_TRUE(graph.full_report->Get(graph.remote_outbound_rtp_id));
3725 const auto& remote_outbound_rtp =
3726 graph.full_report->Get(graph.remote_outbound_rtp_id)
3727 ->cast_to<RTCRemoteOutboundRtpStreamStats>();
3728 EXPECT_EQ(remote_outbound_rtp.timestamp_us(),
3729 kRemoteOutboundStatsTimestampMs * rtc::kNumMicrosecsPerMillisec);
3730 EXPECT_FLOAT_EQ(*remote_outbound_rtp.remote_timestamp,
3731 static_cast<double>(kRemoteOutboundStatsRemoteTimestampMs));
3732 EXPECT_EQ(*remote_outbound_rtp.packets_sent, kRemoteOutboundStatsPacketsSent);
3733 EXPECT_EQ(*remote_outbound_rtp.bytes_sent, kRemoteOutboundStatsBytesSent);
3734 EXPECT_EQ(*remote_outbound_rtp.reports_sent,
3735 kRemoteOutboundStatsReportsCount);
3736}
3737
Henrik Boström646fda02019-05-22 13:49:423738TEST_F(RTCStatsCollectorTest,
3739 RTCVideoSourceStatsNotCollectedForSenderWithoutTrack) {
3740 const uint32_t kSsrc = 4;
3741 const int kAttachmentId = 42;
3742
3743 cricket::VideoMediaInfo video_media_info;
3744 video_media_info.senders.push_back(cricket::VideoSenderInfo());
3745 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3746 video_media_info.senders[0].local_stats[0].ssrc = kSsrc;
Byoungchan Leeefe46b62021-11-10 02:23:563747 video_media_info.senders[0].framerate_input = 29.0;
Tommi19015512022-02-02 10:49:353748 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström646fda02019-05-22 13:49:423749
3750 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
3751 cricket::MEDIA_TYPE_VIDEO, /*track=*/nullptr, kSsrc, kAttachmentId, {});
Tommi6589def2022-02-17 22:36:473752 EXPECT_CALL(*sender, Stop());
3753 EXPECT_CALL(*sender, SetMediaChannel(_));
Henrik Boström646fda02019-05-22 13:49:423754 pc_->AddSender(sender);
3755
3756 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Henrik Boström8dfc90f2022-09-02 07:39:293757 EXPECT_FALSE(report->Get("SV42"));
Henrik Boström646fda02019-05-22 13:49:423758}
3759
Taylor Brandstetter64851c02021-06-24 20:32:503760// Test collecting echo return loss stats from the audio processor attached to
3761// the track, rather than the voice sender info.
3762TEST_F(RTCStatsCollectorTest, CollectEchoReturnLossFromTrackAudioProcessor) {
3763 rtc::scoped_refptr<MediaStream> local_stream =
3764 MediaStream::Create("LocalStreamId");
3765 pc_->mutable_local_streams()->AddStream(local_stream);
3766
3767 // Local audio track
3768 rtc::scoped_refptr<MediaStreamTrackInterface> local_audio_track =
3769 CreateFakeTrack(cricket::MEDIA_TYPE_AUDIO, "LocalAudioTrackID",
3770 MediaStreamTrackInterface::kEnded,
3771 /*create_fake_audio_processor=*/true);
Harald Alvestrand2f7ad282022-04-21 11:35:433772 local_stream->AddTrack(rtc::scoped_refptr<AudioTrackInterface>(
3773 static_cast<AudioTrackInterface*>(local_audio_track.get())));
Taylor Brandstetter64851c02021-06-24 20:32:503774
3775 cricket::VoiceSenderInfo voice_sender_info_ssrc1;
3776 voice_sender_info_ssrc1.local_stats.push_back(cricket::SsrcSenderInfo());
3777 voice_sender_info_ssrc1.local_stats[0].ssrc = 1;
3778
3779 stats_->CreateMockRtpSendersReceiversAndChannels(
3780 {std::make_pair(local_audio_track.get(), voice_sender_info_ssrc1)}, {},
3781 {}, {}, {local_stream->id()}, {});
3782
3783 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3784
Henrik Boström15166b22022-10-19 09:06:583785 DEPRECATED_RTCMediaStreamTrackStats expected_local_audio_track_ssrc1(
3786 IdForType<DEPRECATED_RTCMediaStreamTrackStats>(report.get()),
3787 report->timestamp_us(), RTCMediaStreamTrackKind::kAudio);
Taylor Brandstetter64851c02021-06-24 20:32:503788 expected_local_audio_track_ssrc1.track_identifier = local_audio_track->id();
3789 expected_local_audio_track_ssrc1.media_source_id =
Henrik Boström8dfc90f2022-09-02 07:39:293790 "SA11"; // Attachment ID = SSRC + 10
Taylor Brandstetter64851c02021-06-24 20:32:503791 expected_local_audio_track_ssrc1.remote_source = false;
3792 expected_local_audio_track_ssrc1.ended = true;
3793 expected_local_audio_track_ssrc1.detached = false;
3794 expected_local_audio_track_ssrc1.echo_return_loss = 2.0;
3795 expected_local_audio_track_ssrc1.echo_return_loss_enhancement = 3.0;
3796 ASSERT_TRUE(report->Get(expected_local_audio_track_ssrc1.id()))
3797 << "Did not find " << expected_local_audio_track_ssrc1.id() << " in "
3798 << report->ToJson();
3799 EXPECT_EQ(expected_local_audio_track_ssrc1,
3800 report->Get(expected_local_audio_track_ssrc1.id())
Henrik Boström15166b22022-10-19 09:06:583801 ->cast_to<DEPRECATED_RTCMediaStreamTrackStats>());
Taylor Brandstetter64851c02021-06-24 20:32:503802
Henrik Boström8dfc90f2022-09-02 07:39:293803 RTCAudioSourceStats expected_audio("SA11", report->timestamp_us());
Taylor Brandstetter64851c02021-06-24 20:32:503804 expected_audio.track_identifier = "LocalAudioTrackID";
3805 expected_audio.kind = "audio";
3806 expected_audio.audio_level = 0;
3807 expected_audio.total_audio_energy = 0;
3808 expected_audio.total_samples_duration = 0;
3809 expected_audio.echo_return_loss = 2.0;
3810 expected_audio.echo_return_loss_enhancement = 3.0;
3811
3812 ASSERT_TRUE(report->Get(expected_audio.id()));
3813 EXPECT_EQ(report->Get(expected_audio.id())->cast_to<RTCAudioSourceStats>(),
3814 expected_audio);
3815}
3816
Henrik Boström5b3541f2018-03-19 12:52:563817TEST_F(RTCStatsCollectorTest, GetStatsWithSenderSelector) {
3818 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
3819 // Expected stats graph when filtered by sender:
3820 //
Henrik Boström646fda02019-05-22 13:49:423821 // +--- track (sender)
3822 // | ^
3823 // | |
3824 // | +--------- outbound-rtp
3825 // | | | |
3826 // | | v v
3827 // | | codec (send) transport
3828 // v v
3829 // media-source
Henrik Boström5b3541f2018-03-19 12:52:563830 rtc::scoped_refptr<const RTCStatsReport> sender_report =
3831 stats_->GetStatsReportWithSenderSelector(graph.sender);
3832 EXPECT_TRUE(sender_report);
3833 EXPECT_EQ(sender_report->timestamp_us(), graph.full_report->timestamp_us());
Henrik Boström646fda02019-05-22 13:49:423834 EXPECT_EQ(sender_report->size(), 5u);
Henrik Boström5b3541f2018-03-19 12:52:563835 EXPECT_TRUE(sender_report->Get(graph.send_codec_id));
3836 EXPECT_FALSE(sender_report->Get(graph.recv_codec_id));
3837 EXPECT_TRUE(sender_report->Get(graph.outbound_rtp_id));
3838 EXPECT_FALSE(sender_report->Get(graph.inbound_rtp_id));
3839 EXPECT_TRUE(sender_report->Get(graph.transport_id));
3840 EXPECT_TRUE(sender_report->Get(graph.sender_track_id));
3841 EXPECT_FALSE(sender_report->Get(graph.receiver_track_id));
3842 EXPECT_FALSE(sender_report->Get(graph.remote_stream_id));
3843 EXPECT_FALSE(sender_report->Get(graph.peer_connection_id));
Henrik Boström646fda02019-05-22 13:49:423844 EXPECT_TRUE(sender_report->Get(graph.media_source_id));
Henrik Boström5b3541f2018-03-19 12:52:563845}
3846
3847TEST_F(RTCStatsCollectorTest, GetStatsWithReceiverSelector) {
3848 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
3849 // Expected stats graph when filtered by receiver:
3850 //
Henrik Boström646fda02019-05-22 13:49:423851 // track (receiver)
3852 // ^
3853 // |
3854 // inbound-rtp ---------------+
3855 // | |
3856 // v v
3857 // transport codec (recv)
Henrik Boström5b3541f2018-03-19 12:52:563858 rtc::scoped_refptr<const RTCStatsReport> receiver_report =
3859 stats_->GetStatsReportWithReceiverSelector(graph.receiver);
3860 EXPECT_TRUE(receiver_report);
3861 EXPECT_EQ(receiver_report->size(), 4u);
3862 EXPECT_EQ(receiver_report->timestamp_us(), graph.full_report->timestamp_us());
3863 EXPECT_FALSE(receiver_report->Get(graph.send_codec_id));
3864 EXPECT_TRUE(receiver_report->Get(graph.recv_codec_id));
3865 EXPECT_FALSE(receiver_report->Get(graph.outbound_rtp_id));
3866 EXPECT_TRUE(receiver_report->Get(graph.inbound_rtp_id));
3867 EXPECT_TRUE(receiver_report->Get(graph.transport_id));
3868 EXPECT_FALSE(receiver_report->Get(graph.sender_track_id));
3869 EXPECT_TRUE(receiver_report->Get(graph.receiver_track_id));
3870 EXPECT_FALSE(receiver_report->Get(graph.remote_stream_id));
3871 EXPECT_FALSE(receiver_report->Get(graph.peer_connection_id));
Henrik Boström646fda02019-05-22 13:49:423872 EXPECT_FALSE(receiver_report->Get(graph.media_source_id));
Henrik Boström5b3541f2018-03-19 12:52:563873}
3874
3875TEST_F(RTCStatsCollectorTest, GetStatsWithNullSenderSelector) {
3876 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
3877 rtc::scoped_refptr<const RTCStatsReport> empty_report =
3878 stats_->GetStatsReportWithSenderSelector(nullptr);
3879 EXPECT_TRUE(empty_report);
3880 EXPECT_EQ(empty_report->timestamp_us(), graph.full_report->timestamp_us());
3881 EXPECT_EQ(empty_report->size(), 0u);
3882}
3883
3884TEST_F(RTCStatsCollectorTest, GetStatsWithNullReceiverSelector) {
3885 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
3886 rtc::scoped_refptr<const RTCStatsReport> empty_report =
3887 stats_->GetStatsReportWithReceiverSelector(nullptr);
3888 EXPECT_TRUE(empty_report);
3889 EXPECT_EQ(empty_report->timestamp_us(), graph.full_report->timestamp_us());
3890 EXPECT_EQ(empty_report->size(), 0u);
3891}
3892
Henrik Boström5ed4da72022-12-24 10:20:123893// Before SetLocalDescription() senders don't have an SSRC.
3894// To simulate this case we create a mock sender with SSRC=0.
3895TEST_F(RTCStatsCollectorTest, RtpIsMissingWhileSsrcIsZero) {
Harald Alvestrand89061872018-01-02 13:08:343896 rtc::scoped_refptr<MediaStreamTrackInterface> track =
3897 CreateFakeTrack(cricket::MEDIA_TYPE_AUDIO, "audioTrack",
3898 MediaStreamTrackInterface::kLive);
Steve Anton57858b32018-02-15 23:19:503899 rtc::scoped_refptr<MockRtpSenderInternal> sender =
Henrik Boström646fda02019-05-22 13:49:423900 CreateMockSender(cricket::MEDIA_TYPE_AUDIO, track, 0, 49, {});
Tommi6589def2022-02-17 22:36:473901 EXPECT_CALL(*sender, Stop());
Steve Anton5b387312018-02-03 00:00:203902 pc_->AddSender(sender);
3903
3904 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3905
Henrik Boström5ed4da72022-12-24 10:20:123906 auto tracks = report->GetStatsOfType<DEPRECATED_RTCMediaStreamTrackStats>();
3907 EXPECT_EQ(1U, tracks.size());
3908 auto outbound_rtps = report->GetStatsOfType<RTCOutboundRTPStreamStats>();
3909 EXPECT_TRUE(outbound_rtps.empty());
Harald Alvestrand89061872018-01-02 13:08:343910}
3911
Henrik Boström5ed4da72022-12-24 10:20:123912// We may also be in a case where the SSRC has been assigned but no
3913// `voice_sender_info` stats exist yet.
3914TEST_F(RTCStatsCollectorTest, DoNotCrashIfSsrcIsKnownButInfosAreStillMissing) {
Harald Alvestrand76d29522018-01-30 13:43:293915 rtc::scoped_refptr<MediaStreamTrackInterface> track =
3916 CreateFakeTrack(cricket::MEDIA_TYPE_AUDIO, "audioTrack",
3917 MediaStreamTrackInterface::kLive);
Steve Anton57858b32018-02-15 23:19:503918 rtc::scoped_refptr<MockRtpSenderInternal> sender =
Henrik Boström646fda02019-05-22 13:49:423919 CreateMockSender(cricket::MEDIA_TYPE_AUDIO, track, 4711, 49, {});
Tommi6589def2022-02-17 22:36:473920 EXPECT_CALL(*sender, Stop());
Steve Anton5b387312018-02-03 00:00:203921 pc_->AddSender(sender);
3922
Harald Alvestrand76d29522018-01-30 13:43:293923 // We do not generate any matching voice_sender_info stats.
Steve Anton5b387312018-02-03 00:00:203924 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3925
Henrik Boström15166b22022-10-19 09:06:583926 std::vector<const DEPRECATED_RTCMediaStreamTrackStats*> track_stats =
3927 report->GetStatsOfType<DEPRECATED_RTCMediaStreamTrackStats>();
Mirko Bonadeie12c1fe2018-07-03 10:53:233928 EXPECT_EQ(1U, track_stats.size());
Henrik Boström5ed4da72022-12-24 10:20:123929 auto outbound_rtps = report->GetStatsOfType<RTCOutboundRTPStreamStats>();
3930 EXPECT_TRUE(outbound_rtps.empty());
Harald Alvestrand76d29522018-01-30 13:43:293931}
3932
Taylor Brandstetter87d5a742018-03-06 17:42:253933// Used for test below, to test calling GetStatsReport during a callback.
Taylor Brandstetter25e022f2018-03-08 17:53:473934class RecursiveCallback : public RTCStatsCollectorCallback {
Taylor Brandstetter87d5a742018-03-06 17:42:253935 public:
Taylor Brandstetter25e022f2018-03-08 17:53:473936 explicit RecursiveCallback(RTCStatsCollectorWrapper* stats) : stats_(stats) {}
Taylor Brandstetter87d5a742018-03-06 17:42:253937
3938 void OnStatsDelivered(
3939 const rtc::scoped_refptr<const RTCStatsReport>& report) override {
3940 stats_->GetStatsReport();
3941 called_ = true;
3942 }
3943
3944 bool called() const { return called_; }
3945
3946 private:
3947 RTCStatsCollectorWrapper* stats_;
3948 bool called_ = false;
3949};
3950
3951// Test that nothing bad happens if a callback causes GetStatsReport to be
3952// called again recursively. Regression test for crbug.com/webrtc/8973.
Taylor Brandstetter25e022f2018-03-08 17:53:473953TEST_F(RTCStatsCollectorTest, DoNotCrashWhenGetStatsCalledDuringCallback) {
Niels Möller027c7932022-01-25 12:56:073954 auto callback1 = rtc::make_ref_counted<RecursiveCallback>(stats_.get());
3955 auto callback2 = rtc::make_ref_counted<RecursiveCallback>(stats_.get());
Taylor Brandstetter87d5a742018-03-06 17:42:253956 stats_->stats_collector()->GetStatsReport(callback1);
3957 stats_->stats_collector()->GetStatsReport(callback2);
3958 EXPECT_TRUE_WAIT(callback1->called(), kGetStatsReportTimeoutMs);
3959 EXPECT_TRUE_WAIT(callback2->called(), kGetStatsReportTimeoutMs);
3960}
3961
Steve Anton5b387312018-02-03 00:00:203962class RTCTestStats : public RTCStats {
hbosc82f2e12016-09-05 08:36:503963 public:
Steve Anton5b387312018-02-03 00:00:203964 WEBRTC_RTCSTATS_DECL();
3965
3966 RTCTestStats(const std::string& id, int64_t timestamp_us)
3967 : RTCStats(id, timestamp_us), dummy_stat("dummyStat") {}
3968
3969 RTCStatsMember<int32_t> dummy_stat;
3970};
3971
Mirko Bonadeic4dd7302019-02-25 08:12:023972WEBRTC_RTCSTATS_IMPL(RTCTestStats, RTCStats, "test-stats", &dummy_stat)
Steve Anton5b387312018-02-03 00:00:203973
3974// Overrides the stats collection to verify thread usage and that the resulting
3975// partial reports are merged.
3976class FakeRTCStatsCollector : public RTCStatsCollector,
3977 public RTCStatsCollectorCallback {
3978 public:
3979 static rtc::scoped_refptr<FakeRTCStatsCollector> Create(
3980 PeerConnectionInternal* pc,
3981 int64_t cache_lifetime_us) {
Niels Möllere7cc8832022-01-04 14:20:033982 return rtc::scoped_refptr<FakeRTCStatsCollector>(
3983 new rtc::RefCountedObject<FakeRTCStatsCollector>(pc,
3984 cache_lifetime_us));
Steve Anton5b387312018-02-03 00:00:203985 }
3986
Tomas Gunnarssone6de5ae2021-04-22 16:16:353987 // Since FakeRTCStatsCollector inherits twice from RefCountInterface, once via
3988 // RTCStatsCollector and once via RTCStatsCollectorCallback, scoped_refptr
3989 // will get confused about which AddRef()/Release() methods to call.
3990 // So to remove all doubt, we declare them here again in the class that we
3991 // give to scoped_refptr.
3992 // Satisfying the implementation of these methods and associating them with a
3993 // reference counter, will be done by RefCountedObject.
3994 virtual void AddRef() const = 0;
3995 virtual rtc::RefCountReleaseStatus Release() const = 0;
3996
Steve Anton5b387312018-02-03 00:00:203997 // RTCStatsCollectorCallback implementation.
3998 void OnStatsDelivered(
3999 const rtc::scoped_refptr<const RTCStatsReport>& report) override {
4000 EXPECT_TRUE(signaling_thread_->IsCurrent());
Markus Handell6fcd0f82020-07-07 17:08:534001 MutexLock lock(&lock_);
Steve Anton5b387312018-02-03 00:00:204002 delivered_report_ = report;
4003 }
4004
4005 void VerifyThreadUsageAndResultsMerging() {
4006 GetStatsReport(rtc::scoped_refptr<RTCStatsCollectorCallback>(this));
4007 EXPECT_TRUE_WAIT(HasVerifiedResults(), kGetStatsReportTimeoutMs);
4008 }
4009
4010 bool HasVerifiedResults() {
4011 EXPECT_TRUE(signaling_thread_->IsCurrent());
Markus Handell6fcd0f82020-07-07 17:08:534012 MutexLock lock(&lock_);
Steve Anton5b387312018-02-03 00:00:204013 if (!delivered_report_)
4014 return false;
4015 EXPECT_EQ(produced_on_signaling_thread_, 1);
4016 EXPECT_EQ(produced_on_network_thread_, 1);
4017
4018 EXPECT_TRUE(delivered_report_->Get("SignalingThreadStats"));
4019 EXPECT_TRUE(delivered_report_->Get("NetworkThreadStats"));
4020
4021 produced_on_signaling_thread_ = 0;
4022 produced_on_network_thread_ = 0;
4023 delivered_report_ = nullptr;
4024 return true;
hbosc82f2e12016-09-05 08:36:504025 }
4026
4027 protected:
Steve Anton5b387312018-02-03 00:00:204028 FakeRTCStatsCollector(PeerConnectionInternal* pc, int64_t cache_lifetime)
4029 : RTCStatsCollector(pc, cache_lifetime),
4030 signaling_thread_(pc->signaling_thread()),
4031 worker_thread_(pc->worker_thread()),
4032 network_thread_(pc->network_thread()) {}
4033
Henrik Boström40b030e2019-02-28 08:49:314034 void ProducePartialResultsOnSignalingThreadImpl(
4035 int64_t timestamp_us,
4036 RTCStatsReport* partial_report) override {
Steve Anton5b387312018-02-03 00:00:204037 EXPECT_TRUE(signaling_thread_->IsCurrent());
4038 {
Markus Handell6fcd0f82020-07-07 17:08:534039 MutexLock lock(&lock_);
Steve Anton5b387312018-02-03 00:00:204040 EXPECT_FALSE(delivered_report_);
4041 ++produced_on_signaling_thread_;
4042 }
4043
Henrik Boström40b030e2019-02-28 08:49:314044 partial_report->AddStats(std::unique_ptr<const RTCStats>(
Steve Anton5b387312018-02-03 00:00:204045 new RTCTestStats("SignalingThreadStats", timestamp_us)));
Steve Anton5b387312018-02-03 00:00:204046 }
Henrik Boström40b030e2019-02-28 08:49:314047 void ProducePartialResultsOnNetworkThreadImpl(
4048 int64_t timestamp_us,
4049 const std::map<std::string, cricket::TransportStats>&
4050 transport_stats_by_name,
4051 const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
4052 RTCStatsReport* partial_report) override {
Steve Anton5b387312018-02-03 00:00:204053 EXPECT_TRUE(network_thread_->IsCurrent());
4054 {
Markus Handell6fcd0f82020-07-07 17:08:534055 MutexLock lock(&lock_);
Steve Anton5b387312018-02-03 00:00:204056 EXPECT_FALSE(delivered_report_);
4057 ++produced_on_network_thread_;
4058 }
4059
Henrik Boström40b030e2019-02-28 08:49:314060 partial_report->AddStats(std::unique_ptr<const RTCStats>(
Steve Anton5b387312018-02-03 00:00:204061 new RTCTestStats("NetworkThreadStats", timestamp_us)));
Steve Anton5b387312018-02-03 00:00:204062 }
4063
4064 private:
4065 rtc::Thread* const signaling_thread_;
4066 rtc::Thread* const worker_thread_;
4067 rtc::Thread* const network_thread_;
4068
Markus Handell6fcd0f82020-07-07 17:08:534069 Mutex lock_;
Steve Anton5b387312018-02-03 00:00:204070 rtc::scoped_refptr<const RTCStatsReport> delivered_report_;
4071 int produced_on_signaling_thread_ = 0;
4072 int produced_on_network_thread_ = 0;
hbosc82f2e12016-09-05 08:36:504073};
4074
Steve Anton5b387312018-02-03 00:00:204075TEST(RTCStatsCollectorTestWithFakeCollector, ThreadUsageAndResultsMerging) {
Niels Möller83830f32022-05-20 07:12:574076 rtc::AutoThread main_thread_;
Niels Möller027c7932022-01-25 12:56:074077 auto pc = rtc::make_ref_counted<FakePeerConnectionForStats>();
Steve Anton5b387312018-02-03 00:00:204078 rtc::scoped_refptr<FakeRTCStatsCollector> stats_collector(
Niels Möllerafb246b2022-04-20 12:26:504079 FakeRTCStatsCollector::Create(pc.get(),
4080 50 * rtc::kNumMicrosecsPerMillisec));
Steve Anton5b387312018-02-03 00:00:204081 stats_collector->VerifyThreadUsageAndResultsMerging();
hbosc82f2e12016-09-05 08:36:504082}
4083
4084} // namespace
4085
hbosd565b732016-08-30 21:04:354086} // namespace webrtc