blob: b75a15f322215381f2784058104fd8307d28823a [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öm175f06f2023-01-05 07:53:16391 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));
Henrik Boström175f06f2023-01-05 07:53:16412 EXPECT_CALL(*receiver, ssrc()).WillRepeatedly(Invoke([ssrc]() {
413 return ssrc;
414 }));
Harald Alvestranda3dab842018-01-14 08:18:58415 EXPECT_CALL(*receiver, streams())
416 .WillRepeatedly(
417 Return(std::vector<rtc::scoped_refptr<MediaStreamInterface>>({})));
418
Yves Gerey665174f2018-06-19 13:03:05419 EXPECT_CALL(*receiver, media_type())
420 .WillRepeatedly(
421 Return(track->kind() == MediaStreamTrackInterface::kAudioKind
422 ? cricket::MEDIA_TYPE_AUDIO
423 : cricket::MEDIA_TYPE_VIDEO));
424 EXPECT_CALL(*receiver, GetParameters()).WillRepeatedly(Invoke([ssrc]() {
425 RtpParameters params;
426 params.encodings.push_back(RtpEncodingParameters());
427 params.encodings[0].ssrc = ssrc;
428 return params;
429 }));
Harald Alvestrandc72af932018-01-11 16:18:19430 EXPECT_CALL(*receiver, AttachmentId()).WillRepeatedly(Return(attachment_id));
Tommi6589def2022-02-17 22:36:47431 EXPECT_CALL(*receiver, Stop()).WillRepeatedly(Return());
hbos9e302742017-01-20 10:47:10432 return receiver;
433}
434
Steve Anton5b387312018-02-03 00:00:20435class RTCStatsCollectorWrapper {
hbosd565b732016-08-30 21:04:35436 public:
Steve Anton5b387312018-02-03 00:00:20437 explicit RTCStatsCollectorWrapper(
438 rtc::scoped_refptr<FakePeerConnectionForStats> pc)
439 : pc_(pc),
440 stats_collector_(
Niels Möllerafb246b2022-04-20 12:26:50441 RTCStatsCollector::Create(pc.get(),
442 50 * rtc::kNumMicrosecsPerMillisec)) {}
hbosd565b732016-08-30 21:04:35443
Steve Anton5b387312018-02-03 00:00:20444 rtc::scoped_refptr<RTCStatsCollector> stats_collector() {
445 return stats_collector_;
hbosd565b732016-08-30 21:04:35446 }
447
Henrik Boström5b3541f2018-03-19 12:52:56448 rtc::scoped_refptr<const RTCStatsReport> GetStatsReport() {
449 rtc::scoped_refptr<RTCStatsObtainer> callback = RTCStatsObtainer::Create();
450 stats_collector_->GetStatsReport(callback);
451 return WaitForReport(callback);
452 }
453
454 rtc::scoped_refptr<const RTCStatsReport> GetStatsReportWithSenderSelector(
455 rtc::scoped_refptr<RtpSenderInternal> selector) {
456 rtc::scoped_refptr<RTCStatsObtainer> callback = RTCStatsObtainer::Create();
457 stats_collector_->GetStatsReport(selector, callback);
458 return WaitForReport(callback);
459 }
460
461 rtc::scoped_refptr<const RTCStatsReport> GetStatsReportWithReceiverSelector(
462 rtc::scoped_refptr<RtpReceiverInternal> selector) {
463 rtc::scoped_refptr<RTCStatsObtainer> callback = RTCStatsObtainer::Create();
464 stats_collector_->GetStatsReport(selector, callback);
465 return WaitForReport(callback);
466 }
467
Steve Anton5b387312018-02-03 00:00:20468 rtc::scoped_refptr<const RTCStatsReport> GetFreshStatsReport() {
469 stats_collector_->ClearCachedStatsReport();
470 return GetStatsReport();
471 }
472
Henrik Boström5b3541f2018-03-19 12:52:56473 rtc::scoped_refptr<MockRtpSenderInternal> SetupLocalTrackAndSender(
474 cricket::MediaType media_type,
475 const std::string& track_id,
476 uint32_t ssrc,
Henrik Boström646fda02019-05-22 13:49:42477 bool add_stream,
478 int attachment_id) {
Harald Alvestrand89061872018-01-02 13:08:34479 rtc::scoped_refptr<MediaStream> local_stream;
480 if (add_stream) {
Seth Hampson845e8782018-03-02 19:34:10481 local_stream = MediaStream::Create("LocalStreamId");
Steve Anton5b387312018-02-03 00:00:20482 pc_->mutable_local_streams()->AddStream(local_stream);
Harald Alvestrand89061872018-01-02 13:08:34483 }
hbos84abeb12017-01-16 14:16:44484
485 rtc::scoped_refptr<MediaStreamTrackInterface> track;
486 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
hbos9e302742017-01-20 10:47:10487 track = CreateFakeTrack(media_type, track_id,
488 MediaStreamTrackInterface::kLive);
Harald Alvestrand89061872018-01-02 13:08:34489 if (add_stream) {
Harald Alvestrand2f7ad282022-04-21 11:35:43490 local_stream->AddTrack(rtc::scoped_refptr<AudioTrackInterface>(
491 static_cast<AudioTrackInterface*>(track.get())));
Harald Alvestrand89061872018-01-02 13:08:34492 }
hbos84abeb12017-01-16 14:16:44493 } else {
hbos9e302742017-01-20 10:47:10494 track = CreateFakeTrack(media_type, track_id,
495 MediaStreamTrackInterface::kLive);
Harald Alvestrand89061872018-01-02 13:08:34496 if (add_stream) {
Harald Alvestrand2f7ad282022-04-21 11:35:43497 local_stream->AddTrack(rtc::scoped_refptr<VideoTrackInterface>(
498 static_cast<VideoTrackInterface*>(track.get())));
Harald Alvestrand89061872018-01-02 13:08:34499 }
hbos84abeb12017-01-16 14:16:44500 }
501
Steve Anton57858b32018-02-15 23:19:50502 rtc::scoped_refptr<MockRtpSenderInternal> sender =
Henrik Boström646fda02019-05-22 13:49:42503 CreateMockSender(media_type, track, ssrc, attachment_id, {});
Tommi6589def2022-02-17 22:36:47504 EXPECT_CALL(*sender, Stop());
505 EXPECT_CALL(*sender, SetMediaChannel(_));
Steve Anton5b387312018-02-03 00:00:20506 pc_->AddSender(sender);
Henrik Boström5b3541f2018-03-19 12:52:56507 return sender;
hbos84abeb12017-01-16 14:16:44508 }
509
Henrik Boström5b3541f2018-03-19 12:52:56510 rtc::scoped_refptr<MockRtpReceiverInternal> SetupRemoteTrackAndReceiver(
511 cricket::MediaType media_type,
512 const std::string& track_id,
513 const std::string& stream_id,
514 uint32_t ssrc) {
hbos84abeb12017-01-16 14:16:44515 rtc::scoped_refptr<MediaStream> remote_stream =
Henrik Boström5b3541f2018-03-19 12:52:56516 MediaStream::Create(stream_id);
Steve Anton5b387312018-02-03 00:00:20517 pc_->mutable_remote_streams()->AddStream(remote_stream);
hbos84abeb12017-01-16 14:16:44518
519 rtc::scoped_refptr<MediaStreamTrackInterface> track;
520 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
hbos9e302742017-01-20 10:47:10521 track = CreateFakeTrack(media_type, track_id,
522 MediaStreamTrackInterface::kLive);
Harald Alvestrand2f7ad282022-04-21 11:35:43523 remote_stream->AddTrack(rtc::scoped_refptr<AudioTrackInterface>(
524 static_cast<AudioTrackInterface*>(track.get())));
hbos84abeb12017-01-16 14:16:44525 } else {
hbos9e302742017-01-20 10:47:10526 track = CreateFakeTrack(media_type, track_id,
527 MediaStreamTrackInterface::kLive);
Harald Alvestrand2f7ad282022-04-21 11:35:43528 remote_stream->AddTrack(rtc::scoped_refptr<VideoTrackInterface>(
529 static_cast<VideoTrackInterface*>(track.get())));
hbos84abeb12017-01-16 14:16:44530 }
531
Steve Anton57858b32018-02-15 23:19:50532 rtc::scoped_refptr<MockRtpReceiverInternal> receiver =
Harald Alvestrandc72af932018-01-11 16:18:19533 CreateMockReceiver(track, ssrc, 62);
Harald Alvestranda3dab842018-01-14 08:18:58534 EXPECT_CALL(*receiver, streams())
535 .WillRepeatedly(
536 Return(std::vector<rtc::scoped_refptr<MediaStreamInterface>>(
537 {remote_stream})));
Tommi6589def2022-02-17 22:36:47538 EXPECT_CALL(*receiver, SetMediaChannel(_)).WillRepeatedly(Return());
Steve Anton5b387312018-02-03 00:00:20539 pc_->AddReceiver(receiver);
Henrik Boström5b3541f2018-03-19 12:52:56540 return receiver;
hbos84abeb12017-01-16 14:16:44541 }
542
hbos9e302742017-01-20 10:47:10543 // Attaches tracks to peer connections by configuring RTP senders and RTP
544 // receivers according to the tracks' pairings with
545 // |[Voice/Video][Sender/Receiver]Info| and their SSRCs. Local tracks can be
546 // associated with multiple |[Voice/Video]SenderInfo|s, remote tracks can only
547 // be associated with one |[Voice/Video]ReceiverInfo|.
Henrik Boström646fda02019-05-22 13:49:42548 // Senders get assigned attachment ID "ssrc + 10".
hbos9e302742017-01-20 10:47:10549 void CreateMockRtpSendersReceiversAndChannels(
Harald Alvestranda3dab842018-01-14 08:18:58550 std::initializer_list<
551 std::pair<MediaStreamTrackInterface*, cricket::VoiceSenderInfo>>
552 local_audio_track_info_pairs,
553 std::initializer_list<
554 std::pair<MediaStreamTrackInterface*, cricket::VoiceReceiverInfo>>
555 remote_audio_track_info_pairs,
556 std::initializer_list<
557 std::pair<MediaStreamTrackInterface*, cricket::VideoSenderInfo>>
558 local_video_track_info_pairs,
559 std::initializer_list<
560 std::pair<MediaStreamTrackInterface*, cricket::VideoReceiverInfo>>
561 remote_video_track_info_pairs,
562 std::vector<std::string> local_stream_ids,
563 std::vector<rtc::scoped_refptr<MediaStreamInterface>> remote_streams) {
Steve Anton5b387312018-02-03 00:00:20564 cricket::VoiceMediaInfo voice_media_info;
565 cricket::VideoMediaInfo video_media_info;
566
hbos9e302742017-01-20 10:47:10567 // Local audio tracks and voice sender infos
568 for (auto& pair : local_audio_track_info_pairs) {
569 MediaStreamTrackInterface* local_audio_track = pair.first;
570 const cricket::VoiceSenderInfo& voice_sender_info = pair.second;
571 RTC_DCHECK_EQ(local_audio_track->kind(),
572 MediaStreamTrackInterface::kAudioKind);
573
Steve Anton5b387312018-02-03 00:00:20574 voice_media_info.senders.push_back(voice_sender_info);
Steve Anton57858b32018-02-15 23:19:50575 rtc::scoped_refptr<MockRtpSenderInternal> rtp_sender = CreateMockSender(
Henrik Boström646fda02019-05-22 13:49:42576 cricket::MEDIA_TYPE_AUDIO,
Harald Alvestrandc72af932018-01-11 16:18:19577 rtc::scoped_refptr<MediaStreamTrackInterface>(local_audio_track),
Henrik Boström646fda02019-05-22 13:49:42578 voice_sender_info.local_stats[0].ssrc,
579 voice_sender_info.local_stats[0].ssrc + 10, local_stream_ids);
Tomas Gunnarsson16de2162022-01-26 09:21:57580 EXPECT_CALL(*rtp_sender, SetMediaChannel(_)).WillRepeatedly(Return());
Tommi6589def2022-02-17 22:36:47581 EXPECT_CALL(*rtp_sender, Stop());
Steve Anton5b387312018-02-03 00:00:20582 pc_->AddSender(rtp_sender);
hbos9e302742017-01-20 10:47:10583 }
Steve Anton5b387312018-02-03 00:00:20584
hbos9e302742017-01-20 10:47:10585 // Remote audio tracks and voice receiver infos
586 for (auto& pair : remote_audio_track_info_pairs) {
587 MediaStreamTrackInterface* remote_audio_track = pair.first;
588 const cricket::VoiceReceiverInfo& voice_receiver_info = pair.second;
589 RTC_DCHECK_EQ(remote_audio_track->kind(),
590 MediaStreamTrackInterface::kAudioKind);
591
Steve Anton5b387312018-02-03 00:00:20592 voice_media_info.receivers.push_back(voice_receiver_info);
Steve Anton57858b32018-02-15 23:19:50593 rtc::scoped_refptr<MockRtpReceiverInternal> rtp_receiver =
594 CreateMockReceiver(
595 rtc::scoped_refptr<MediaStreamTrackInterface>(remote_audio_track),
Henrik Boström646fda02019-05-22 13:49:42596 voice_receiver_info.local_stats[0].ssrc,
597 voice_receiver_info.local_stats[0].ssrc + 10);
Harald Alvestranda3dab842018-01-14 08:18:58598 EXPECT_CALL(*rtp_receiver, streams())
599 .WillRepeatedly(Return(remote_streams));
Tommi6589def2022-02-17 22:36:47600 EXPECT_CALL(*rtp_receiver, SetMediaChannel(_)).WillRepeatedly(Return());
Steve Anton5b387312018-02-03 00:00:20601 pc_->AddReceiver(rtp_receiver);
hbos9e302742017-01-20 10:47:10602 }
Steve Anton5b387312018-02-03 00:00:20603
hbos9e302742017-01-20 10:47:10604 // Local video tracks and video sender infos
605 for (auto& pair : local_video_track_info_pairs) {
606 MediaStreamTrackInterface* local_video_track = pair.first;
607 const cricket::VideoSenderInfo& video_sender_info = pair.second;
608 RTC_DCHECK_EQ(local_video_track->kind(),
609 MediaStreamTrackInterface::kVideoKind);
610
Steve Anton5b387312018-02-03 00:00:20611 video_media_info.senders.push_back(video_sender_info);
Henrik Boströma0ff50c2020-05-05 13:54:46612 video_media_info.aggregated_senders.push_back(video_sender_info);
Steve Anton57858b32018-02-15 23:19:50613 rtc::scoped_refptr<MockRtpSenderInternal> rtp_sender = CreateMockSender(
Henrik Boström646fda02019-05-22 13:49:42614 cricket::MEDIA_TYPE_VIDEO,
Harald Alvestrandc72af932018-01-11 16:18:19615 rtc::scoped_refptr<MediaStreamTrackInterface>(local_video_track),
Henrik Boström646fda02019-05-22 13:49:42616 video_sender_info.local_stats[0].ssrc,
617 video_sender_info.local_stats[0].ssrc + 10, local_stream_ids);
Tomas Gunnarsson16de2162022-01-26 09:21:57618 EXPECT_CALL(*rtp_sender, SetMediaChannel(_)).WillRepeatedly(Return());
Tommi6589def2022-02-17 22:36:47619 EXPECT_CALL(*rtp_sender, Stop());
Steve Anton5b387312018-02-03 00:00:20620 pc_->AddSender(rtp_sender);
hbos9e302742017-01-20 10:47:10621 }
Steve Anton5b387312018-02-03 00:00:20622
hbos9e302742017-01-20 10:47:10623 // Remote video tracks and video receiver infos
624 for (auto& pair : remote_video_track_info_pairs) {
625 MediaStreamTrackInterface* remote_video_track = pair.first;
626 const cricket::VideoReceiverInfo& video_receiver_info = pair.second;
627 RTC_DCHECK_EQ(remote_video_track->kind(),
628 MediaStreamTrackInterface::kVideoKind);
629
Steve Anton5b387312018-02-03 00:00:20630 video_media_info.receivers.push_back(video_receiver_info);
Steve Anton57858b32018-02-15 23:19:50631 rtc::scoped_refptr<MockRtpReceiverInternal> rtp_receiver =
632 CreateMockReceiver(
633 rtc::scoped_refptr<MediaStreamTrackInterface>(remote_video_track),
Henrik Boström646fda02019-05-22 13:49:42634 video_receiver_info.local_stats[0].ssrc,
635 video_receiver_info.local_stats[0].ssrc + 10);
Harald Alvestranda3dab842018-01-14 08:18:58636 EXPECT_CALL(*rtp_receiver, streams())
637 .WillRepeatedly(Return(remote_streams));
Tommi6589def2022-02-17 22:36:47638 EXPECT_CALL(*rtp_receiver, SetMediaChannel(_)).WillRepeatedly(Return());
Steve Anton5b387312018-02-03 00:00:20639 pc_->AddReceiver(rtp_receiver);
hbos9e302742017-01-20 10:47:10640 }
hbos9e302742017-01-20 10:47:10641
Tommi19015512022-02-02 10:49:35642 pc_->AddVoiceChannel("audio", "transport", voice_media_info);
643 pc_->AddVideoChannel("video", "transport", video_media_info);
hbos9e302742017-01-20 10:47:10644 }
645
hbosd565b732016-08-30 21:04:35646 private:
Henrik Boström5b3541f2018-03-19 12:52:56647 rtc::scoped_refptr<const RTCStatsReport> WaitForReport(
648 rtc::scoped_refptr<RTCStatsObtainer> callback) {
Niels Möllerafb246b2022-04-20 12:26:50649 EXPECT_TRUE_WAIT(callback->report() != nullptr, kGetStatsReportTimeoutMs);
Henrik Boström5b3541f2018-03-19 12:52:56650 int64_t after = rtc::TimeUTCMicros();
651 for (const RTCStats& stats : *callback->report()) {
Alessio Bazzicaf7b1b952021-03-23 16:23:04652 if (stats.type() == RTCRemoteInboundRtpStreamStats::kType ||
653 stats.type() == RTCRemoteOutboundRtpStreamStats::kType) {
654 // Ignore remote timestamps.
655 continue;
656 }
Philipp Hanckeb81823a2023-01-04 14:17:42657 EXPECT_LE(stats.timestamp().us(), after);
Henrik Boström5b3541f2018-03-19 12:52:56658 }
659 return callback->report();
660 }
661
Steve Anton5b387312018-02-03 00:00:20662 rtc::scoped_refptr<FakePeerConnectionForStats> pc_;
663 rtc::scoped_refptr<RTCStatsCollector> stats_collector_;
hbosd565b732016-08-30 21:04:35664};
665
Mirko Bonadei6a489f22019-04-09 13:11:12666class RTCStatsCollectorTest : public ::testing::Test {
hbosc82f2e12016-09-05 08:36:50667 public:
668 RTCStatsCollectorTest()
Niels Möller027c7932022-01-25 12:56:07669 : pc_(rtc::make_ref_counted<FakePeerConnectionForStats>()),
Steve Anton5b387312018-02-03 00:00:20670 stats_(new RTCStatsCollectorWrapper(pc_)) {}
hbosc82f2e12016-09-05 08:36:50671
hbos6ab97ce02016-10-03 21:16:56672 void ExpectReportContainsCertificateInfo(
673 const rtc::scoped_refptr<const RTCStatsReport>& report,
hbos23368e12016-12-21 12:29:17674 const CertificateInfo& certinfo) {
675 for (size_t i = 0; i < certinfo.fingerprints.size(); ++i) {
676 RTCCertificateStats expected_certificate_stats(
Philipp Hanckeb81823a2023-01-04 14:17:42677 "CF" + certinfo.fingerprints[i], report->timestamp());
hbos23368e12016-12-21 12:29:17678 expected_certificate_stats.fingerprint = certinfo.fingerprints[i];
679 expected_certificate_stats.fingerprint_algorithm = "sha-1";
680 expected_certificate_stats.base64_certificate = certinfo.pems[i];
681 if (i + 1 < certinfo.fingerprints.size()) {
682 expected_certificate_stats.issuer_certificate_id =
Henrik Boström8dfc90f2022-09-02 07:39:29683 "CF" + certinfo.fingerprints[i + 1];
hbos6ab97ce02016-10-03 21:16:56684 }
hbos23368e12016-12-21 12:29:17685 ASSERT_TRUE(report->Get(expected_certificate_stats.id()));
686 EXPECT_EQ(expected_certificate_stats,
Yves Gerey665174f2018-06-19 13:03:05687 report->Get(expected_certificate_stats.id())
688 ->cast_to<RTCCertificateStats>());
hbos6ab97ce02016-10-03 21:16:56689 }
690 }
691
Henrik Boström69d23c92022-09-26 12:13:17692 const RTCCertificateStats* GetCertificateStatsFromFingerprint(
693 const rtc::scoped_refptr<const RTCStatsReport>& report,
694 const std::string& fingerprint) {
695 auto certificates = report->GetStatsOfType<RTCCertificateStats>();
696 for (const auto* certificate : certificates) {
697 if (*certificate->fingerprint == fingerprint) {
698 return certificate;
699 }
700 }
701 return nullptr;
702 }
703
Henrik Boström5b3541f2018-03-19 12:52:56704 struct ExampleStatsGraph {
705 rtc::scoped_refptr<RtpSenderInternal> sender;
706 rtc::scoped_refptr<RtpReceiverInternal> receiver;
707
708 rtc::scoped_refptr<const RTCStatsReport> full_report;
709 std::string send_codec_id;
710 std::string recv_codec_id;
711 std::string outbound_rtp_id;
712 std::string inbound_rtp_id;
Alessio Bazzicaf7b1b952021-03-23 16:23:04713 std::string remote_outbound_rtp_id;
Henrik Boström5b3541f2018-03-19 12:52:56714 std::string transport_id;
715 std::string sender_track_id;
716 std::string receiver_track_id;
717 std::string remote_stream_id;
718 std::string peer_connection_id;
Henrik Boström646fda02019-05-22 13:49:42719 std::string media_source_id;
Henrik Boström5b3541f2018-03-19 12:52:56720 };
721
Alessio Bazzicaf7b1b952021-03-23 16:23:04722 // Sets up the example stats graph (see ASCII art below) for a video only
723 // call. The graph is used for testing the stats selection algorithm (see
724 // https://w3c.github.io/webrtc-pc/#dfn-stats-selection-algorithm).
Henrik Boström5b3541f2018-03-19 12:52:56725 // These tests test the integration of the stats traversal algorithm inside of
726 // RTCStatsCollector. See rtcstatstraveral_unittest.cc for more stats
727 // traversal tests.
728 ExampleStatsGraph SetupExampleStatsGraphForSelectorTests() {
729 ExampleStatsGraph graph;
730
731 // codec (send)
Henrik Boström8dfc90f2022-09-02 07:39:29732 graph.send_codec_id = "COTTransportName1_1";
Henrik Boström5b3541f2018-03-19 12:52:56733 cricket::VideoMediaInfo video_media_info;
734 RtpCodecParameters send_codec;
735 send_codec.payload_type = 1;
736 send_codec.clock_rate = 0;
737 video_media_info.send_codecs.insert(
738 std::make_pair(send_codec.payload_type, send_codec));
739 // codec (recv)
Henrik Boström8dfc90f2022-09-02 07:39:29740 graph.recv_codec_id = "CITTransportName1_2";
Henrik Boström5b3541f2018-03-19 12:52:56741 RtpCodecParameters recv_codec;
742 recv_codec.payload_type = 2;
743 recv_codec.clock_rate = 0;
744 video_media_info.receive_codecs.insert(
745 std::make_pair(recv_codec.payload_type, recv_codec));
746 // outbound-rtp
Henrik Boströmb43e3bb2022-09-26 10:36:44747 graph.outbound_rtp_id = "OTTransportName1V3";
Henrik Boström5b3541f2018-03-19 12:52:56748 video_media_info.senders.push_back(cricket::VideoSenderInfo());
749 video_media_info.senders[0].local_stats.push_back(
750 cricket::SsrcSenderInfo());
751 video_media_info.senders[0].local_stats[0].ssrc = 3;
752 video_media_info.senders[0].codec_payload_type = send_codec.payload_type;
Henrik Boströma0ff50c2020-05-05 13:54:46753 video_media_info.aggregated_senders.push_back(video_media_info.senders[0]);
Henrik Boström5b3541f2018-03-19 12:52:56754 // inbound-rtp
Henrik Boströmb43e3bb2022-09-26 10:36:44755 graph.inbound_rtp_id = "ITTransportName1V4";
Henrik Boström5b3541f2018-03-19 12:52:56756 video_media_info.receivers.push_back(cricket::VideoReceiverInfo());
757 video_media_info.receivers[0].local_stats.push_back(
758 cricket::SsrcReceiverInfo());
759 video_media_info.receivers[0].local_stats[0].ssrc = 4;
760 video_media_info.receivers[0].codec_payload_type = recv_codec.payload_type;
761 // transport
Henrik Boström8dfc90f2022-09-02 07:39:29762 graph.transport_id = "TTransportName1";
Tommi19015512022-02-02 10:49:35763 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström5b3541f2018-03-19 12:52:56764 // track (sender)
765 graph.sender = stats_->SetupLocalTrackAndSender(
Henrik Boström646fda02019-05-22 13:49:42766 cricket::MEDIA_TYPE_VIDEO, "LocalVideoTrackID", 3, false, 50);
Henrik Boström8dfc90f2022-09-02 07:39:29767 graph.sender_track_id =
768 "DEPRECATED_TO" + rtc::ToString(graph.sender->AttachmentId());
Henrik Boström5b3541f2018-03-19 12:52:56769 // track (receiver) and stream (remote stream)
770 graph.receiver = stats_->SetupRemoteTrackAndReceiver(
771 cricket::MEDIA_TYPE_VIDEO, "RemoteVideoTrackID", "RemoteStreamId", 4);
Henrik Boström8dfc90f2022-09-02 07:39:29772 graph.receiver_track_id =
773 "DEPRECATED_TI" + rtc::ToString(graph.receiver->AttachmentId());
774 graph.remote_stream_id = "DEPRECATED_SRemoteStreamId";
Henrik Boström5b3541f2018-03-19 12:52:56775 // peer-connection
Henrik Boström8dfc90f2022-09-02 07:39:29776 graph.peer_connection_id = "P";
Henrik Boström646fda02019-05-22 13:49:42777 // media-source (kind: video)
Henrik Boström8dfc90f2022-09-02 07:39:29778 graph.media_source_id = "SV" + rtc::ToString(graph.sender->AttachmentId());
Henrik Boström5b3541f2018-03-19 12:52:56779
780 // Expected stats graph:
781 //
Henrik Boström646fda02019-05-22 13:49:42782 // +--- track (sender) stream (remote stream) ---> track (receiver)
783 // | ^ ^
784 // | | |
785 // | +--------- outbound-rtp inbound-rtp ---------------+
786 // | | | | | |
787 // | | v v v v
788 // | | codec (send) transport codec (recv) peer-connection
789 // v v
790 // media-source
Henrik Boström5b3541f2018-03-19 12:52:56791
792 // Verify the stats graph is set up correctly.
793 graph.full_report = stats_->GetStatsReport();
Henrik Boström646fda02019-05-22 13:49:42794 EXPECT_EQ(graph.full_report->size(), 10u);
Henrik Boström5b3541f2018-03-19 12:52:56795 EXPECT_TRUE(graph.full_report->Get(graph.send_codec_id));
796 EXPECT_TRUE(graph.full_report->Get(graph.recv_codec_id));
797 EXPECT_TRUE(graph.full_report->Get(graph.outbound_rtp_id));
798 EXPECT_TRUE(graph.full_report->Get(graph.inbound_rtp_id));
799 EXPECT_TRUE(graph.full_report->Get(graph.transport_id));
800 EXPECT_TRUE(graph.full_report->Get(graph.sender_track_id));
801 EXPECT_TRUE(graph.full_report->Get(graph.receiver_track_id));
802 EXPECT_TRUE(graph.full_report->Get(graph.remote_stream_id));
803 EXPECT_TRUE(graph.full_report->Get(graph.peer_connection_id));
Henrik Boström646fda02019-05-22 13:49:42804 EXPECT_TRUE(graph.full_report->Get(graph.media_source_id));
Henrik Boström15166b22022-10-19 09:06:58805 const auto& sender_track =
806 graph.full_report->Get(graph.sender_track_id)
807 ->cast_to<DEPRECATED_RTCMediaStreamTrackStats>();
Henrik Boström646fda02019-05-22 13:49:42808 EXPECT_EQ(*sender_track.media_source_id, graph.media_source_id);
Henrik Boström5b3541f2018-03-19 12:52:56809 const auto& outbound_rtp = graph.full_report->Get(graph.outbound_rtp_id)
810 ->cast_to<RTCOutboundRTPStreamStats>();
Henrik Boström646fda02019-05-22 13:49:42811 EXPECT_EQ(*outbound_rtp.media_source_id, graph.media_source_id);
Henrik Boström5b3541f2018-03-19 12:52:56812 EXPECT_EQ(*outbound_rtp.codec_id, graph.send_codec_id);
813 EXPECT_EQ(*outbound_rtp.track_id, graph.sender_track_id);
814 EXPECT_EQ(*outbound_rtp.transport_id, graph.transport_id);
815 const auto& inbound_rtp = graph.full_report->Get(graph.inbound_rtp_id)
816 ->cast_to<RTCInboundRTPStreamStats>();
817 EXPECT_EQ(*inbound_rtp.codec_id, graph.recv_codec_id);
818 EXPECT_EQ(*inbound_rtp.track_id, graph.receiver_track_id);
819 EXPECT_EQ(*inbound_rtp.transport_id, graph.transport_id);
820
821 return graph;
822 }
823
Alessio Bazzicaf7b1b952021-03-23 16:23:04824 // Sets up an example stats graph (see ASCII art below) for an audio only call
825 // and checks that the expected stats are generated.
826 ExampleStatsGraph SetupExampleStatsVoiceGraph(
827 bool add_remote_outbound_stats) {
828 constexpr uint32_t kLocalSsrc = 3;
829 constexpr uint32_t kRemoteSsrc = 4;
830 ExampleStatsGraph graph;
831
832 // codec (send)
Henrik Boström8dfc90f2022-09-02 07:39:29833 graph.send_codec_id = "COTTransportName1_1";
Alessio Bazzicaf7b1b952021-03-23 16:23:04834 cricket::VoiceMediaInfo media_info;
835 RtpCodecParameters send_codec;
836 send_codec.payload_type = 1;
837 send_codec.clock_rate = 0;
838 media_info.send_codecs.insert(
839 std::make_pair(send_codec.payload_type, send_codec));
840 // codec (recv)
Henrik Boström8dfc90f2022-09-02 07:39:29841 graph.recv_codec_id = "CITTransportName1_2";
Alessio Bazzicaf7b1b952021-03-23 16:23:04842 RtpCodecParameters recv_codec;
843 recv_codec.payload_type = 2;
844 recv_codec.clock_rate = 0;
845 media_info.receive_codecs.insert(
846 std::make_pair(recv_codec.payload_type, recv_codec));
847 // outbound-rtp
Henrik Boströmb43e3bb2022-09-26 10:36:44848 graph.outbound_rtp_id = "OTTransportName1A3";
Alessio Bazzicaf7b1b952021-03-23 16:23:04849 media_info.senders.push_back(cricket::VoiceSenderInfo());
850 media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
851 media_info.senders[0].local_stats[0].ssrc = kLocalSsrc;
852 media_info.senders[0].codec_payload_type = send_codec.payload_type;
853 // inbound-rtp
Henrik Boströmb43e3bb2022-09-26 10:36:44854 graph.inbound_rtp_id = "ITTransportName1A4";
Alessio Bazzicaf7b1b952021-03-23 16:23:04855 media_info.receivers.push_back(cricket::VoiceReceiverInfo());
856 media_info.receivers[0].local_stats.push_back(cricket::SsrcReceiverInfo());
857 media_info.receivers[0].local_stats[0].ssrc = kRemoteSsrc;
858 media_info.receivers[0].codec_payload_type = recv_codec.payload_type;
859 // remote-outbound-rtp
860 if (add_remote_outbound_stats) {
Henrik Boström8dfc90f2022-09-02 07:39:29861 graph.remote_outbound_rtp_id = "ROA4";
Alessio Bazzicaf7b1b952021-03-23 16:23:04862 media_info.receivers[0].last_sender_report_timestamp_ms =
863 kRemoteOutboundStatsTimestampMs;
864 media_info.receivers[0].last_sender_report_remote_timestamp_ms =
865 kRemoteOutboundStatsRemoteTimestampMs;
866 media_info.receivers[0].sender_reports_packets_sent =
867 kRemoteOutboundStatsPacketsSent;
868 media_info.receivers[0].sender_reports_bytes_sent =
869 kRemoteOutboundStatsBytesSent;
870 media_info.receivers[0].sender_reports_reports_count =
871 kRemoteOutboundStatsReportsCount;
872 }
873
874 // transport
Henrik Boström8dfc90f2022-09-02 07:39:29875 graph.transport_id = "TTransportName1";
Tommi19015512022-02-02 10:49:35876 pc_->AddVoiceChannel("VoiceMid", "TransportName", media_info);
Alessio Bazzicaf7b1b952021-03-23 16:23:04877 // track (sender)
878 graph.sender = stats_->SetupLocalTrackAndSender(
879 cricket::MEDIA_TYPE_AUDIO, "LocalAudioTrackID", kLocalSsrc, false, 50);
Henrik Boström8dfc90f2022-09-02 07:39:29880 graph.sender_track_id =
881 "DEPRECATED_TO" + rtc::ToString(graph.sender->AttachmentId());
Alessio Bazzicaf7b1b952021-03-23 16:23:04882 // track (receiver) and stream (remote stream)
883 graph.receiver = stats_->SetupRemoteTrackAndReceiver(
884 cricket::MEDIA_TYPE_AUDIO, "RemoteAudioTrackID", "RemoteStreamId",
885 kRemoteSsrc);
Henrik Boström8dfc90f2022-09-02 07:39:29886 graph.receiver_track_id =
887 "DEPRECATED_TI" + rtc::ToString(graph.receiver->AttachmentId());
888 graph.remote_stream_id = "DEPRECATED_SRemoteStreamId";
Alessio Bazzicaf7b1b952021-03-23 16:23:04889 // peer-connection
Henrik Boström8dfc90f2022-09-02 07:39:29890 graph.peer_connection_id = "P";
Alessio Bazzicaf7b1b952021-03-23 16:23:04891 // media-source (kind: video)
Henrik Boström8dfc90f2022-09-02 07:39:29892 graph.media_source_id = "SA" + rtc::ToString(graph.sender->AttachmentId());
Alessio Bazzicaf7b1b952021-03-23 16:23:04893
894 // Expected stats graph:
895 //
896 // +--- track (sender) stream (remote stream) ---> track (receiver)
897 // | ^ ^
898 // | | |
899 // | +--------- outbound-rtp inbound-rtp ---------------+
900 // | | | | | |
901 // | | v v v v
902 // | | codec (send) transport codec (recv) peer-connection
903 // v v
904 // media-source
905
906 // Verify the stats graph is set up correctly.
907 graph.full_report = stats_->GetStatsReport();
908 EXPECT_EQ(graph.full_report->size(), add_remote_outbound_stats ? 11u : 10u);
909 EXPECT_TRUE(graph.full_report->Get(graph.send_codec_id));
910 EXPECT_TRUE(graph.full_report->Get(graph.recv_codec_id));
911 EXPECT_TRUE(graph.full_report->Get(graph.outbound_rtp_id));
912 EXPECT_TRUE(graph.full_report->Get(graph.inbound_rtp_id));
913 EXPECT_TRUE(graph.full_report->Get(graph.transport_id));
914 EXPECT_TRUE(graph.full_report->Get(graph.sender_track_id));
915 EXPECT_TRUE(graph.full_report->Get(graph.receiver_track_id));
916 EXPECT_TRUE(graph.full_report->Get(graph.remote_stream_id));
917 EXPECT_TRUE(graph.full_report->Get(graph.peer_connection_id));
918 EXPECT_TRUE(graph.full_report->Get(graph.media_source_id));
919 // `graph.remote_outbound_rtp_id` is omitted on purpose so that expectations
920 // can be added by the caller depending on what value it sets for the
921 // `add_remote_outbound_stats` argument.
Henrik Boström15166b22022-10-19 09:06:58922 const auto& sender_track =
923 graph.full_report->Get(graph.sender_track_id)
924 ->cast_to<DEPRECATED_RTCMediaStreamTrackStats>();
Alessio Bazzicaf7b1b952021-03-23 16:23:04925 EXPECT_EQ(*sender_track.media_source_id, graph.media_source_id);
926 const auto& outbound_rtp = graph.full_report->Get(graph.outbound_rtp_id)
927 ->cast_to<RTCOutboundRTPStreamStats>();
928 EXPECT_EQ(*outbound_rtp.media_source_id, graph.media_source_id);
929 EXPECT_EQ(*outbound_rtp.codec_id, graph.send_codec_id);
930 EXPECT_EQ(*outbound_rtp.track_id, graph.sender_track_id);
931 EXPECT_EQ(*outbound_rtp.transport_id, graph.transport_id);
932 const auto& inbound_rtp = graph.full_report->Get(graph.inbound_rtp_id)
933 ->cast_to<RTCInboundRTPStreamStats>();
934 EXPECT_EQ(*inbound_rtp.codec_id, graph.recv_codec_id);
935 EXPECT_EQ(*inbound_rtp.track_id, graph.receiver_track_id);
936 EXPECT_EQ(*inbound_rtp.transport_id, graph.transport_id);
937
938 return graph;
939 }
940
hbosc82f2e12016-09-05 08:36:50941 protected:
Steve Anton5b387312018-02-03 00:00:20942 rtc::ScopedFakeClock fake_clock_;
Niels Möller83830f32022-05-20 07:12:57943 rtc::AutoThread main_thread_;
Steve Anton5b387312018-02-03 00:00:20944 rtc::scoped_refptr<FakePeerConnectionForStats> pc_;
945 std::unique_ptr<RTCStatsCollectorWrapper> stats_;
hbosc82f2e12016-09-05 08:36:50946};
947
948TEST_F(RTCStatsCollectorTest, SingleCallback) {
949 rtc::scoped_refptr<const RTCStatsReport> result;
Steve Anton5b387312018-02-03 00:00:20950 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&result));
Niels Möllerafb246b2022-04-20 12:26:50951 EXPECT_TRUE_WAIT(result != nullptr, kGetStatsReportTimeoutMs);
hbosc82f2e12016-09-05 08:36:50952}
953
954TEST_F(RTCStatsCollectorTest, MultipleCallbacks) {
Steve Anton5b387312018-02-03 00:00:20955 rtc::scoped_refptr<const RTCStatsReport> a, b, c;
956 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&a));
957 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&b));
958 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&c));
Niels Möllerafb246b2022-04-20 12:26:50959 EXPECT_TRUE_WAIT(a != nullptr, kGetStatsReportTimeoutMs);
960 EXPECT_TRUE_WAIT(b != nullptr, kGetStatsReportTimeoutMs);
961 EXPECT_TRUE_WAIT(c != nullptr, kGetStatsReportTimeoutMs);
Steve Anton5b387312018-02-03 00:00:20962
hbosc82f2e12016-09-05 08:36:50963 EXPECT_EQ(a.get(), b.get());
964 EXPECT_EQ(b.get(), c.get());
965}
966
967TEST_F(RTCStatsCollectorTest, CachedStatsReports) {
Artem Titov880fa812021-07-30 20:30:23968 // Caching should ensure `a` and `b` are the same report.
Steve Anton5b387312018-02-03 00:00:20969 rtc::scoped_refptr<const RTCStatsReport> a = stats_->GetStatsReport();
970 rtc::scoped_refptr<const RTCStatsReport> b = stats_->GetStatsReport();
hbosd565b732016-08-30 21:04:35971 EXPECT_EQ(a.get(), b.get());
972 // Invalidate cache by clearing it.
Steve Anton5b387312018-02-03 00:00:20973 stats_->stats_collector()->ClearCachedStatsReport();
974 rtc::scoped_refptr<const RTCStatsReport> c = stats_->GetStatsReport();
hbosd565b732016-08-30 21:04:35975 EXPECT_NE(b.get(), c.get());
976 // Invalidate cache by advancing time.
Danil Chapovalov0c626af2020-02-10 10:16:00977 fake_clock_.AdvanceTime(TimeDelta::Millis(51));
Steve Anton5b387312018-02-03 00:00:20978 rtc::scoped_refptr<const RTCStatsReport> d = stats_->GetStatsReport();
hbosd565b732016-08-30 21:04:35979 EXPECT_TRUE(d);
980 EXPECT_NE(c.get(), d.get());
981}
982
hbosc82f2e12016-09-05 08:36:50983TEST_F(RTCStatsCollectorTest, MultipleCallbacksWithInvalidatedCacheInBetween) {
Steve Anton5b387312018-02-03 00:00:20984 rtc::scoped_refptr<const RTCStatsReport> a, b, c;
985 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&a));
986 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&b));
hbosc82f2e12016-09-05 08:36:50987 // Cache is invalidated after 50 ms.
Danil Chapovalov0c626af2020-02-10 10:16:00988 fake_clock_.AdvanceTime(TimeDelta::Millis(51));
Steve Anton5b387312018-02-03 00:00:20989 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&c));
Niels Möllerafb246b2022-04-20 12:26:50990 EXPECT_TRUE_WAIT(a != nullptr, kGetStatsReportTimeoutMs);
991 EXPECT_TRUE_WAIT(b != nullptr, kGetStatsReportTimeoutMs);
992 EXPECT_TRUE_WAIT(c != nullptr, kGetStatsReportTimeoutMs);
hbosc82f2e12016-09-05 08:36:50993 EXPECT_EQ(a.get(), b.get());
Artem Titov880fa812021-07-30 20:30:23994 // The act of doing `AdvanceTime` processes all messages. If this was not the
995 // case we might not require `c` to be fresher than `b`.
hbosc82f2e12016-09-05 08:36:50996 EXPECT_NE(c.get(), b.get());
997}
998
Harald Alvestrand910cdc22020-01-09 11:58:23999TEST_F(RTCStatsCollectorTest, ToJsonProducesParseableJson) {
1000 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
1001 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1002 std::string json_format = report->ToJson();
Mirko Bonadeie99f6872021-06-24 13:24:591003
1004 Json::CharReaderBuilder builder;
Harald Alvestrand910cdc22020-01-09 11:58:231005 Json::Value json_value;
Mirko Bonadeie99f6872021-06-24 13:24:591006 std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
1007 ASSERT_TRUE(reader->parse(json_format.c_str(),
1008 json_format.c_str() + json_format.size(),
1009 &json_value, nullptr));
1010
Harald Alvestrand910cdc22020-01-09 11:58:231011 // A very brief sanity check on the result.
1012 EXPECT_EQ(report->size(), json_value.size());
1013}
1014
hbos6ab97ce02016-10-03 21:16:561015TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsSingle) {
Steve Anton5b387312018-02-03 00:00:201016 const char kTransportName[] = "transport";
1017
1018 pc_->AddVoiceChannel("audio", kTransportName);
1019
hbos6ab97ce02016-10-03 21:16:561020 std::unique_ptr<CertificateInfo> local_certinfo =
1021 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 13:03:051022 std::vector<std::string>({"(local) single certificate"}));
Steve Anton5b387312018-02-03 00:00:201023 pc_->SetLocalCertificate(kTransportName, local_certinfo->certificate);
1024
hbos6ab97ce02016-10-03 21:16:561025 std::unique_ptr<CertificateInfo> remote_certinfo =
1026 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 13:03:051027 std::vector<std::string>({"(remote) single certificate"}));
Taylor Brandstetterc3928662018-02-23 21:04:511028 pc_->SetRemoteCertChain(
Benjamin Wright6c6c9df2018-10-25 08:16:261029 kTransportName,
1030 remote_certinfo->certificate->GetSSLCertificateChain().Clone());
hbos6ab97ce02016-10-03 21:16:561031
Steve Anton5b387312018-02-03 00:00:201032 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos6ab97ce02016-10-03 21:16:561033
hbos23368e12016-12-21 12:29:171034 ExpectReportContainsCertificateInfo(report, *local_certinfo);
1035 ExpectReportContainsCertificateInfo(report, *remote_certinfo);
hbos6ab97ce02016-10-03 21:16:561036}
1037
Henrik Boströmda6297d2022-09-19 09:33:231038// These SSRC collisions are legal.
1039TEST_F(RTCStatsCollectorTest, ValidSsrcCollisionDoesNotCrash) {
1040 // BUNDLE audio/video inbound/outbound. Unique SSRCs needed within the BUNDLE.
1041 cricket::VoiceMediaInfo mid1_info;
1042 mid1_info.receivers.emplace_back();
1043 mid1_info.receivers[0].add_ssrc(1);
1044 mid1_info.senders.emplace_back();
1045 mid1_info.senders[0].add_ssrc(2);
1046 pc_->AddVoiceChannel("Mid1", "Transport1", mid1_info);
1047 cricket::VideoMediaInfo mid2_info;
1048 mid2_info.receivers.emplace_back();
1049 mid2_info.receivers[0].add_ssrc(3);
1050 mid2_info.senders.emplace_back();
1051 mid2_info.senders[0].add_ssrc(4);
1052 pc_->AddVideoChannel("Mid2", "Transport1", mid2_info);
1053 // Now create a second BUNDLE group with SSRCs colliding with the first group
1054 // (but again no collisions within the group).
1055 cricket::VoiceMediaInfo mid3_info;
1056 mid3_info.receivers.emplace_back();
1057 mid3_info.receivers[0].add_ssrc(1);
1058 mid3_info.senders.emplace_back();
1059 mid3_info.senders[0].add_ssrc(2);
1060 pc_->AddVoiceChannel("Mid3", "Transport2", mid3_info);
1061 cricket::VideoMediaInfo mid4_info;
1062 mid4_info.receivers.emplace_back();
1063 mid4_info.receivers[0].add_ssrc(3);
1064 mid4_info.senders.emplace_back();
1065 mid4_info.senders[0].add_ssrc(4);
1066 pc_->AddVideoChannel("Mid4", "Transport2", mid4_info);
1067
1068 // This should not crash (https://crbug.com/1361612).
1069 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1070 auto inbound_rtps = report->GetStatsOfType<RTCInboundRTPStreamStats>();
1071 auto outbound_rtps = report->GetStatsOfType<RTCOutboundRTPStreamStats>();
Henrik Boströmb43e3bb2022-09-26 10:36:441072 EXPECT_EQ(inbound_rtps.size(), 4u);
1073 EXPECT_EQ(outbound_rtps.size(), 4u);
Henrik Boströmda6297d2022-09-19 09:33:231074}
1075
1076// These SSRC collisions are illegal, so it is not clear if this setup can
1077// happen even when talking to a malicious endpoint, but simulate illegal SSRC
1078// collisions just to make sure we don't crash in even the most extreme cases.
1079TEST_F(RTCStatsCollectorTest, InvalidSsrcCollisionDoesNotCrash) {
1080 // One SSRC to rule them all.
1081 cricket::VoiceMediaInfo mid1_info;
1082 mid1_info.receivers.emplace_back();
1083 mid1_info.receivers[0].add_ssrc(1);
1084 mid1_info.senders.emplace_back();
1085 mid1_info.senders[0].add_ssrc(1);
1086 pc_->AddVoiceChannel("Mid1", "BundledTransport", mid1_info);
1087 cricket::VideoMediaInfo mid2_info;
1088 mid2_info.receivers.emplace_back();
1089 mid2_info.receivers[0].add_ssrc(1);
1090 mid2_info.senders.emplace_back();
1091 mid2_info.senders[0].add_ssrc(1);
1092 pc_->AddVideoChannel("Mid2", "BundledTransport", mid2_info);
1093 cricket::VoiceMediaInfo mid3_info;
1094 mid3_info.receivers.emplace_back();
1095 mid3_info.receivers[0].add_ssrc(1);
1096 mid3_info.senders.emplace_back();
1097 mid3_info.senders[0].add_ssrc(1);
1098 pc_->AddVoiceChannel("Mid3", "BundledTransport", mid3_info);
1099 cricket::VideoMediaInfo mid4_info;
1100 mid4_info.receivers.emplace_back();
1101 mid4_info.receivers[0].add_ssrc(1);
1102 mid4_info.senders.emplace_back();
1103 mid4_info.senders[0].add_ssrc(1);
1104 pc_->AddVideoChannel("Mid4", "BundledTransport", mid4_info);
1105
1106 // This should not crash (https://crbug.com/1361612).
1107 stats_->GetStatsReport();
1108 // Because this setup is illegal, there is no "right answer" to how the report
1109 // should look. We only care about not crashing.
1110}
1111
Henrik Boström31c373b2022-09-26 12:56:211112TEST_F(RTCStatsCollectorTest, CollectRTCCodecStatsOnlyIfReferenced) {
hbos0adb8282016-11-23 10:32:061113 // Audio
1114 cricket::VoiceMediaInfo voice_media_info;
1115
1116 RtpCodecParameters inbound_audio_codec;
1117 inbound_audio_codec.payload_type = 1;
deadbeefe702b302017-02-04 20:09:011118 inbound_audio_codec.kind = cricket::MEDIA_TYPE_AUDIO;
1119 inbound_audio_codec.name = "opus";
Oskar Sundbomcbc71b22017-11-16 09:56:071120 inbound_audio_codec.clock_rate = 1337;
Johannes Kron72d69152020-02-10 13:05:551121 inbound_audio_codec.num_channels = 1;
1122 inbound_audio_codec.parameters = {{"minptime", "10"}, {"useinbandfec", "1"}};
hbos0adb8282016-11-23 10:32:061123 voice_media_info.receive_codecs.insert(
1124 std::make_pair(inbound_audio_codec.payload_type, inbound_audio_codec));
1125
1126 RtpCodecParameters outbound_audio_codec;
1127 outbound_audio_codec.payload_type = 2;
deadbeefe702b302017-02-04 20:09:011128 outbound_audio_codec.kind = cricket::MEDIA_TYPE_AUDIO;
1129 outbound_audio_codec.name = "isac";
Oskar Sundbomcbc71b22017-11-16 09:56:071130 outbound_audio_codec.clock_rate = 1338;
Johannes Kron72d69152020-02-10 13:05:551131 outbound_audio_codec.num_channels = 2;
hbos0adb8282016-11-23 10:32:061132 voice_media_info.send_codecs.insert(
1133 std::make_pair(outbound_audio_codec.payload_type, outbound_audio_codec));
1134
hbos0adb8282016-11-23 10:32:061135 // Video
1136 cricket::VideoMediaInfo video_media_info;
1137
1138 RtpCodecParameters inbound_video_codec;
1139 inbound_video_codec.payload_type = 3;
deadbeefe702b302017-02-04 20:09:011140 inbound_video_codec.kind = cricket::MEDIA_TYPE_VIDEO;
1141 inbound_video_codec.name = "H264";
Oskar Sundbomcbc71b22017-11-16 09:56:071142 inbound_video_codec.clock_rate = 1339;
Johannes Kron72d69152020-02-10 13:05:551143 inbound_video_codec.parameters = {{"level-asymmetry-allowed", "1"},
1144 {"packetization-mode", "1"},
1145 {"profile-level-id", "42001f"}};
hbos0adb8282016-11-23 10:32:061146 video_media_info.receive_codecs.insert(
1147 std::make_pair(inbound_video_codec.payload_type, inbound_video_codec));
1148
1149 RtpCodecParameters outbound_video_codec;
1150 outbound_video_codec.payload_type = 4;
deadbeefe702b302017-02-04 20:09:011151 outbound_video_codec.kind = cricket::MEDIA_TYPE_VIDEO;
1152 outbound_video_codec.name = "VP8";
Oskar Sundbomcbc71b22017-11-16 09:56:071153 outbound_video_codec.clock_rate = 1340;
hbos0adb8282016-11-23 10:32:061154 video_media_info.send_codecs.insert(
1155 std::make_pair(outbound_video_codec.payload_type, outbound_video_codec));
1156
Henrik Boström31c373b2022-09-26 12:56:211157 // Ensure the above codecs are referenced.
1158 cricket::VoiceReceiverInfo inbound_audio_info;
1159 inbound_audio_info.add_ssrc(10);
1160 inbound_audio_info.codec_payload_type = 1;
1161 voice_media_info.receivers.push_back(inbound_audio_info);
1162
1163 cricket::VoiceSenderInfo outbound_audio_info;
1164 outbound_audio_info.add_ssrc(20);
1165 outbound_audio_info.codec_payload_type = 2;
1166 voice_media_info.senders.push_back(outbound_audio_info);
1167
1168 cricket::VideoReceiverInfo inbound_video_info;
1169 inbound_video_info.add_ssrc(30);
1170 inbound_video_info.codec_payload_type = 3;
1171 video_media_info.receivers.push_back(inbound_video_info);
1172
1173 cricket::VideoSenderInfo outbound_video_info;
1174 outbound_video_info.add_ssrc(40);
1175 outbound_video_info.codec_payload_type = 4;
1176 video_media_info.senders.push_back(outbound_video_info);
1177
1178 FakeVoiceMediaChannelForStats* audio_channel =
1179 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
1180 FakeVideoMediaChannelForStats* video_channel =
1181 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
hbos0adb8282016-11-23 10:32:061182
Steve Anton5b387312018-02-03 00:00:201183 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos0adb8282016-11-23 10:32:061184
Henrik Boströmb2be3922022-09-02 07:37:081185 RTCCodecStats expected_inbound_audio_codec(
Philipp Hanckeb81823a2023-01-04 14:17:421186 "CITTransportName1_1_minptime=10;useinbandfec=1", report->timestamp());
hbos0adb8282016-11-23 10:32:061187 expected_inbound_audio_codec.payload_type = 1;
hbos13f54b22017-02-28 14:56:041188 expected_inbound_audio_codec.mime_type = "audio/opus";
hbos0adb8282016-11-23 10:32:061189 expected_inbound_audio_codec.clock_rate = 1337;
Johannes Kron72d69152020-02-10 13:05:551190 expected_inbound_audio_codec.channels = 1;
1191 expected_inbound_audio_codec.sdp_fmtp_line = "minptime=10;useinbandfec=1";
Henrik Boström8dfc90f2022-09-02 07:39:291192 expected_inbound_audio_codec.transport_id = "TTransportName1";
hbos0adb8282016-11-23 10:32:061193
Henrik Boström8dfc90f2022-09-02 07:39:291194 RTCCodecStats expected_outbound_audio_codec("COTTransportName1_2",
Philipp Hanckeb81823a2023-01-04 14:17:421195 report->timestamp());
hbos0adb8282016-11-23 10:32:061196 expected_outbound_audio_codec.payload_type = 2;
hbos13f54b22017-02-28 14:56:041197 expected_outbound_audio_codec.mime_type = "audio/isac";
hbos0adb8282016-11-23 10:32:061198 expected_outbound_audio_codec.clock_rate = 1338;
Johannes Kron72d69152020-02-10 13:05:551199 expected_outbound_audio_codec.channels = 2;
Henrik Boström8dfc90f2022-09-02 07:39:291200 expected_outbound_audio_codec.transport_id = "TTransportName1";
hbos0adb8282016-11-23 10:32:061201
Henrik Boströmb2be3922022-09-02 07:37:081202 RTCCodecStats expected_inbound_video_codec(
Henrik Boström8dfc90f2022-09-02 07:39:291203 "CITTransportName1_3_level-asymmetry-allowed=1;"
Henrik Boströmb2be3922022-09-02 07:37:081204 "packetization-mode=1;profile-level-id=42001f",
Philipp Hanckeb81823a2023-01-04 14:17:421205 report->timestamp());
hbos0adb8282016-11-23 10:32:061206 expected_inbound_video_codec.payload_type = 3;
hbos13f54b22017-02-28 14:56:041207 expected_inbound_video_codec.mime_type = "video/H264";
hbos0adb8282016-11-23 10:32:061208 expected_inbound_video_codec.clock_rate = 1339;
Johannes Kron72d69152020-02-10 13:05:551209 expected_inbound_video_codec.sdp_fmtp_line =
1210 "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f";
Henrik Boström8dfc90f2022-09-02 07:39:291211 expected_inbound_video_codec.transport_id = "TTransportName1";
hbos0adb8282016-11-23 10:32:061212
Henrik Boström8dfc90f2022-09-02 07:39:291213 RTCCodecStats expected_outbound_video_codec("COTTransportName1_4",
Philipp Hanckeb81823a2023-01-04 14:17:421214 report->timestamp());
hbos0adb8282016-11-23 10:32:061215 expected_outbound_video_codec.payload_type = 4;
hbos13f54b22017-02-28 14:56:041216 expected_outbound_video_codec.mime_type = "video/VP8";
hbos0adb8282016-11-23 10:32:061217 expected_outbound_video_codec.clock_rate = 1340;
Henrik Boström8dfc90f2022-09-02 07:39:291218 expected_outbound_video_codec.transport_id = "TTransportName1";
hbos0adb8282016-11-23 10:32:061219
nissec8ee8822017-01-18 15:20:551220 ASSERT_TRUE(report->Get(expected_inbound_audio_codec.id()));
Yves Gerey665174f2018-06-19 13:03:051221 EXPECT_EQ(
1222 expected_inbound_audio_codec,
1223 report->Get(expected_inbound_audio_codec.id())->cast_to<RTCCodecStats>());
hbos0adb8282016-11-23 10:32:061224
nissec8ee8822017-01-18 15:20:551225 ASSERT_TRUE(report->Get(expected_outbound_audio_codec.id()));
hbos0adb8282016-11-23 10:32:061226 EXPECT_EQ(expected_outbound_audio_codec,
Yves Gerey665174f2018-06-19 13:03:051227 report->Get(expected_outbound_audio_codec.id())
1228 ->cast_to<RTCCodecStats>());
hbos0adb8282016-11-23 10:32:061229
nissec8ee8822017-01-18 15:20:551230 ASSERT_TRUE(report->Get(expected_inbound_video_codec.id()));
Yves Gerey665174f2018-06-19 13:03:051231 EXPECT_EQ(
1232 expected_inbound_video_codec,
1233 report->Get(expected_inbound_video_codec.id())->cast_to<RTCCodecStats>());
hbos0adb8282016-11-23 10:32:061234
nissec8ee8822017-01-18 15:20:551235 ASSERT_TRUE(report->Get(expected_outbound_video_codec.id()));
hbos0adb8282016-11-23 10:32:061236 EXPECT_EQ(expected_outbound_video_codec,
Yves Gerey665174f2018-06-19 13:03:051237 report->Get(expected_outbound_video_codec.id())
1238 ->cast_to<RTCCodecStats>());
Henrik Boström31c373b2022-09-26 12:56:211239
1240 // Now remove all the RTP streams such that there are no live codecId
1241 // references to the codecs, this should result in none of the RTCCodecStats
1242 // being exposed, despite `send_codecs` and `receive_codecs` still being set.
1243 voice_media_info.senders.clear();
1244 voice_media_info.receivers.clear();
1245 audio_channel->SetStats(voice_media_info);
1246 video_media_info.senders.clear();
1247 video_media_info.receivers.clear();
1248 video_channel->SetStats(video_media_info);
1249 stats_->stats_collector()->ClearCachedStatsReport();
1250 report = stats_->GetStatsReport();
1251 EXPECT_FALSE(report->Get(expected_inbound_audio_codec.id()));
1252 EXPECT_FALSE(report->Get(expected_outbound_audio_codec.id()));
1253 EXPECT_FALSE(report->Get(expected_inbound_video_codec.id()));
1254 EXPECT_FALSE(report->Get(expected_outbound_video_codec.id()));
hbos0adb8282016-11-23 10:32:061255}
1256
Henrik Boströmb2be3922022-09-02 07:37:081257TEST_F(RTCStatsCollectorTest, CodecStatsAreCollectedPerTransport) {
1258 // PT=10
1259 RtpCodecParameters outbound_codec_pt10;
1260 outbound_codec_pt10.payload_type = 10;
1261 outbound_codec_pt10.kind = cricket::MEDIA_TYPE_VIDEO;
1262 outbound_codec_pt10.name = "VP8";
1263 outbound_codec_pt10.clock_rate = 9000;
1264
1265 // PT=11
1266 RtpCodecParameters outbound_codec_pt11;
1267 outbound_codec_pt11.payload_type = 11;
1268 outbound_codec_pt11.kind = cricket::MEDIA_TYPE_VIDEO;
1269 outbound_codec_pt11.name = "VP8";
1270 outbound_codec_pt11.clock_rate = 9000;
1271
Henrik Boström31c373b2022-09-26 12:56:211272 // Insert codecs into `send_codecs` and ensure the PTs are referenced by RTP
1273 // streams.
Henrik Boströmb2be3922022-09-02 07:37:081274 cricket::VideoMediaInfo info_pt10;
1275 info_pt10.send_codecs.insert(
1276 std::make_pair(outbound_codec_pt10.payload_type, outbound_codec_pt10));
Henrik Boström31c373b2022-09-26 12:56:211277 info_pt10.senders.emplace_back();
1278 info_pt10.senders[0].add_ssrc(42);
1279 info_pt10.senders[0].codec_payload_type = outbound_codec_pt10.payload_type;
1280
Henrik Boströmb2be3922022-09-02 07:37:081281 cricket::VideoMediaInfo info_pt11;
1282 info_pt11.send_codecs.insert(
1283 std::make_pair(outbound_codec_pt11.payload_type, outbound_codec_pt11));
Henrik Boström31c373b2022-09-26 12:56:211284 info_pt11.senders.emplace_back();
1285 info_pt11.senders[0].add_ssrc(43);
1286 info_pt11.senders[0].codec_payload_type = outbound_codec_pt11.payload_type;
1287
Henrik Boströmb2be3922022-09-02 07:37:081288 cricket::VideoMediaInfo info_pt10_pt11;
1289 info_pt10_pt11.send_codecs.insert(
1290 std::make_pair(outbound_codec_pt10.payload_type, outbound_codec_pt10));
1291 info_pt10_pt11.send_codecs.insert(
1292 std::make_pair(outbound_codec_pt11.payload_type, outbound_codec_pt11));
Henrik Boström31c373b2022-09-26 12:56:211293 info_pt10_pt11.senders.emplace_back();
1294 info_pt10_pt11.senders[0].add_ssrc(44);
1295 info_pt10_pt11.senders[0].codec_payload_type =
1296 outbound_codec_pt10.payload_type;
1297 info_pt10_pt11.senders.emplace_back();
1298 info_pt10_pt11.senders[1].add_ssrc(45);
1299 info_pt10_pt11.senders[1].codec_payload_type =
1300 outbound_codec_pt11.payload_type;
Henrik Boströmb2be3922022-09-02 07:37:081301
1302 // First two mids contain subsets, the third one contains all PTs.
1303 pc_->AddVideoChannel("Mid1", "FirstTransport", info_pt10);
1304 pc_->AddVideoChannel("Mid2", "FirstTransport", info_pt11);
1305 pc_->AddVideoChannel("Mid3", "FirstTransport", info_pt10_pt11);
1306
1307 // There should be no duplicate codecs because all codec references are on the
1308 // same transport.
1309 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1310 auto codec_stats = report->GetStatsOfType<RTCCodecStats>();
1311 EXPECT_EQ(codec_stats.size(), 2u);
1312
1313 // If a second transport is added with the same PT information, this does
1314 // count as different codec objects.
1315 pc_->AddVideoChannel("Mid4", "SecondTransport", info_pt10_pt11);
1316 stats_->stats_collector()->ClearCachedStatsReport();
1317 report = stats_->GetStatsReport();
1318 codec_stats = report->GetStatsOfType<RTCCodecStats>();
1319 EXPECT_EQ(codec_stats.size(), 4u);
1320}
1321
1322TEST_F(RTCStatsCollectorTest, SamePayloadTypeButDifferentFmtpLines) {
1323 // PT=111, useinbandfec=0
1324 RtpCodecParameters inbound_codec_pt111_nofec;
1325 inbound_codec_pt111_nofec.payload_type = 111;
1326 inbound_codec_pt111_nofec.kind = cricket::MEDIA_TYPE_AUDIO;
1327 inbound_codec_pt111_nofec.name = "opus";
1328 inbound_codec_pt111_nofec.clock_rate = 48000;
1329 inbound_codec_pt111_nofec.parameters.insert(
1330 std::make_pair("useinbandfec", "0"));
1331
1332 // PT=111, useinbandfec=1
1333 RtpCodecParameters inbound_codec_pt111_fec;
1334 inbound_codec_pt111_fec.payload_type = 111;
1335 inbound_codec_pt111_fec.kind = cricket::MEDIA_TYPE_AUDIO;
1336 inbound_codec_pt111_fec.name = "opus";
1337 inbound_codec_pt111_fec.clock_rate = 48000;
1338 inbound_codec_pt111_fec.parameters.insert(
1339 std::make_pair("useinbandfec", "1"));
1340
1341 cricket::VideoMediaInfo info_nofec;
Henrik Boström31c373b2022-09-26 12:56:211342 info_nofec.receive_codecs.insert(std::make_pair(
Henrik Boströmb2be3922022-09-02 07:37:081343 inbound_codec_pt111_nofec.payload_type, inbound_codec_pt111_nofec));
Henrik Boström31c373b2022-09-26 12:56:211344 info_nofec.receivers.emplace_back();
1345 info_nofec.receivers[0].add_ssrc(123);
1346 info_nofec.receivers[0].codec_payload_type =
1347 inbound_codec_pt111_nofec.payload_type;
Henrik Boströmb2be3922022-09-02 07:37:081348 cricket::VideoMediaInfo info_fec;
Henrik Boström31c373b2022-09-26 12:56:211349 info_fec.receive_codecs.insert(std::make_pair(
Henrik Boströmb2be3922022-09-02 07:37:081350 inbound_codec_pt111_fec.payload_type, inbound_codec_pt111_fec));
Henrik Boström31c373b2022-09-26 12:56:211351 info_fec.receivers.emplace_back();
1352 info_fec.receivers[0].add_ssrc(321);
1353 info_fec.receivers[0].codec_payload_type =
1354 inbound_codec_pt111_fec.payload_type;
Henrik Boströmb2be3922022-09-02 07:37:081355
1356 // First two mids contain subsets, the third one contains all PTs.
1357 pc_->AddVideoChannel("Mid1", "BundledTransport", info_nofec);
1358 pc_->AddVideoChannel("Mid2", "BundledTransport", info_fec);
1359
1360 // Despite having the same PT we should see two codec stats because their FMTP
1361 // lines are different.
1362 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1363 auto codec_stats = report->GetStatsOfType<RTCCodecStats>();
1364 EXPECT_EQ(codec_stats.size(), 2u);
1365
Henrik Boström31c373b2022-09-26 12:56:211366 // Ensure SSRC uniqueness before the next AddVideoChannel() call. SSRCs need
1367 // to be unique on different m= sections when using BUNDLE.
1368 info_nofec.receivers[0].local_stats[0].ssrc = 12;
1369 info_fec.receivers[0].local_stats[0].ssrc = 21;
Henrik Boströmb2be3922022-09-02 07:37:081370 // Adding more m= sections that does have the same FMTP lines does not result
1371 // in duplicates.
1372 pc_->AddVideoChannel("Mid3", "BundledTransport", info_nofec);
1373 pc_->AddVideoChannel("Mid4", "BundledTransport", info_fec);
1374 stats_->stats_collector()->ClearCachedStatsReport();
1375 report = stats_->GetStatsReport();
1376 codec_stats = report->GetStatsOfType<RTCCodecStats>();
1377 EXPECT_EQ(codec_stats.size(), 2u);
1378
1379 // Same FMTP line but a different PT does count as a new codec.
1380 // PT=112, useinbandfec=1
1381 RtpCodecParameters inbound_codec_pt112_fec;
1382 inbound_codec_pt112_fec.payload_type = 112;
1383 inbound_codec_pt112_fec.kind = cricket::MEDIA_TYPE_AUDIO;
1384 inbound_codec_pt112_fec.name = "opus";
1385 inbound_codec_pt112_fec.clock_rate = 48000;
1386 inbound_codec_pt112_fec.parameters.insert(
1387 std::make_pair("useinbandfec", "1"));
1388 cricket::VideoMediaInfo info_fec_pt112;
Henrik Boström31c373b2022-09-26 12:56:211389 info_fec_pt112.receive_codecs.insert(std::make_pair(
Henrik Boströmb2be3922022-09-02 07:37:081390 inbound_codec_pt112_fec.payload_type, inbound_codec_pt112_fec));
Henrik Boström31c373b2022-09-26 12:56:211391 info_fec_pt112.receivers.emplace_back();
1392 info_fec_pt112.receivers[0].add_ssrc(112);
1393 info_fec_pt112.receivers[0].codec_payload_type =
1394 inbound_codec_pt112_fec.payload_type;
Henrik Boströmb2be3922022-09-02 07:37:081395 pc_->AddVideoChannel("Mid5", "BundledTransport", info_fec_pt112);
1396 stats_->stats_collector()->ClearCachedStatsReport();
1397 report = stats_->GetStatsReport();
1398 codec_stats = report->GetStatsOfType<RTCCodecStats>();
1399 EXPECT_EQ(codec_stats.size(), 3u);
1400}
1401
hbos6ab97ce02016-10-03 21:16:561402TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsMultiple) {
Steve Anton5b387312018-02-03 00:00:201403 const char kAudioTransport[] = "audio";
1404 const char kVideoTransport[] = "video";
1405
1406 pc_->AddVoiceChannel("audio", kAudioTransport);
Tommi19015512022-02-02 10:49:351407
hbos6ab97ce02016-10-03 21:16:561408 std::unique_ptr<CertificateInfo> audio_local_certinfo =
1409 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 13:03:051410 std::vector<std::string>({"(local) audio"}));
Steve Anton5b387312018-02-03 00:00:201411 pc_->SetLocalCertificate(kAudioTransport, audio_local_certinfo->certificate);
hbos6ab97ce02016-10-03 21:16:561412 std::unique_ptr<CertificateInfo> audio_remote_certinfo =
1413 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 13:03:051414 std::vector<std::string>({"(remote) audio"}));
Taylor Brandstetterc3928662018-02-23 21:04:511415 pc_->SetRemoteCertChain(
1416 kAudioTransport,
Benjamin Wright6c6c9df2018-10-25 08:16:261417 audio_remote_certinfo->certificate->GetSSLCertificateChain().Clone());
hbos6ab97ce02016-10-03 21:16:561418
Steve Anton5b387312018-02-03 00:00:201419 pc_->AddVideoChannel("video", kVideoTransport);
hbos6ab97ce02016-10-03 21:16:561420 std::unique_ptr<CertificateInfo> video_local_certinfo =
1421 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 13:03:051422 std::vector<std::string>({"(local) video"}));
Steve Anton5b387312018-02-03 00:00:201423 pc_->SetLocalCertificate(kVideoTransport, video_local_certinfo->certificate);
hbos6ab97ce02016-10-03 21:16:561424 std::unique_ptr<CertificateInfo> video_remote_certinfo =
1425 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 13:03:051426 std::vector<std::string>({"(remote) video"}));
Taylor Brandstetterc3928662018-02-23 21:04:511427 pc_->SetRemoteCertChain(
1428 kVideoTransport,
Benjamin Wright6c6c9df2018-10-25 08:16:261429 video_remote_certinfo->certificate->GetSSLCertificateChain().Clone());
hbos6ab97ce02016-10-03 21:16:561430
Steve Anton5b387312018-02-03 00:00:201431 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos23368e12016-12-21 12:29:171432 ExpectReportContainsCertificateInfo(report, *audio_local_certinfo);
1433 ExpectReportContainsCertificateInfo(report, *audio_remote_certinfo);
1434 ExpectReportContainsCertificateInfo(report, *video_local_certinfo);
1435 ExpectReportContainsCertificateInfo(report, *video_remote_certinfo);
hbos6ab97ce02016-10-03 21:16:561436}
1437
1438TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsChain) {
Steve Anton5b387312018-02-03 00:00:201439 const char kTransportName[] = "transport";
1440
1441 pc_->AddVoiceChannel("audio", kTransportName);
1442
hbos6ab97ce02016-10-03 21:16:561443 std::unique_ptr<CertificateInfo> local_certinfo =
Steve Anton5b387312018-02-03 00:00:201444 CreateFakeCertificateAndInfoFromDers(
1445 {"(local) this", "(local) is", "(local) a", "(local) chain"});
1446 pc_->SetLocalCertificate(kTransportName, local_certinfo->certificate);
1447
hbos6ab97ce02016-10-03 21:16:561448 std::unique_ptr<CertificateInfo> remote_certinfo =
Steve Anton5b387312018-02-03 00:00:201449 CreateFakeCertificateAndInfoFromDers({"(remote) this", "(remote) is",
1450 "(remote) another",
1451 "(remote) chain"});
Taylor Brandstetterc3928662018-02-23 21:04:511452 pc_->SetRemoteCertChain(
Benjamin Wright6c6c9df2018-10-25 08:16:261453 kTransportName,
1454 remote_certinfo->certificate->GetSSLCertificateChain().Clone());
hbos6ab97ce02016-10-03 21:16:561455
Steve Anton5b387312018-02-03 00:00:201456 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos23368e12016-12-21 12:29:171457 ExpectReportContainsCertificateInfo(report, *local_certinfo);
1458 ExpectReportContainsCertificateInfo(report, *remote_certinfo);
hbos6ab97ce02016-10-03 21:16:561459}
1460
Henrik Boström69d23c92022-09-26 12:13:171461TEST_F(RTCStatsCollectorTest, CertificateStatsCache) {
1462 const char kTransportName[] = "transport";
1463 rtc::ScopedFakeClock fake_clock;
1464
1465 pc_->AddVoiceChannel("audio", kTransportName);
1466
1467 // Set local and remote cerificates.
1468 std::unique_ptr<CertificateInfo> initial_local_certinfo =
1469 CreateFakeCertificateAndInfoFromDers({"LocalCertA", "LocalCertB"});
1470 pc_->SetLocalCertificate(kTransportName, initial_local_certinfo->certificate);
1471 std::unique_ptr<CertificateInfo> initial_remote_certinfo =
1472 CreateFakeCertificateAndInfoFromDers({"RemoteCertA", "RemoteCertB"});
1473 pc_->SetRemoteCertChain(
1474 kTransportName,
1475 initial_remote_certinfo->certificate->GetSSLCertificateChain().Clone());
1476 ASSERT_EQ(initial_local_certinfo->fingerprints.size(), 2u);
1477 ASSERT_EQ(initial_remote_certinfo->fingerprints.size(), 2u);
1478
1479 rtc::scoped_refptr<const RTCStatsReport> first_report =
1480 stats_->GetStatsReport();
1481 const auto* first_local_cert0 = GetCertificateStatsFromFingerprint(
1482 first_report, initial_local_certinfo->fingerprints[0]);
1483 const auto* first_local_cert1 = GetCertificateStatsFromFingerprint(
1484 first_report, initial_local_certinfo->fingerprints[1]);
1485 const auto* first_remote_cert0 = GetCertificateStatsFromFingerprint(
1486 first_report, initial_remote_certinfo->fingerprints[0]);
1487 const auto* first_remote_cert1 = GetCertificateStatsFromFingerprint(
1488 first_report, initial_remote_certinfo->fingerprints[1]);
1489 ASSERT_TRUE(first_local_cert0);
1490 ASSERT_TRUE(first_local_cert1);
1491 ASSERT_TRUE(first_remote_cert0);
1492 ASSERT_TRUE(first_remote_cert1);
Philipp Hanckeb81823a2023-01-04 14:17:421493 EXPECT_EQ(first_local_cert0->timestamp().us(), rtc::TimeMicros());
1494 EXPECT_EQ(first_local_cert1->timestamp().us(), rtc::TimeMicros());
1495 EXPECT_EQ(first_remote_cert0->timestamp().us(), rtc::TimeMicros());
1496 EXPECT_EQ(first_remote_cert1->timestamp().us(), rtc::TimeMicros());
Henrik Boström69d23c92022-09-26 12:13:171497
1498 // Replace all certificates.
1499 std::unique_ptr<CertificateInfo> updated_local_certinfo =
1500 CreateFakeCertificateAndInfoFromDers(
1501 {"UpdatedLocalCertA", "UpdatedLocalCertB"});
1502 pc_->SetLocalCertificate(kTransportName, updated_local_certinfo->certificate);
1503 std::unique_ptr<CertificateInfo> updated_remote_certinfo =
1504 CreateFakeCertificateAndInfoFromDers(
1505 {"UpdatedRemoteCertA", "UpdatedRemoteCertB"});
1506 pc_->SetRemoteCertChain(
1507 kTransportName,
1508 updated_remote_certinfo->certificate->GetSSLCertificateChain().Clone());
1509 // This test assumes fingerprints are different for the old and new
1510 // certificates.
1511 EXPECT_NE(initial_local_certinfo->fingerprints,
1512 updated_local_certinfo->fingerprints);
1513 EXPECT_NE(initial_remote_certinfo->fingerprints,
1514 updated_remote_certinfo->fingerprints);
1515
1516 // Advance time to ensure a fresh stats report, but don't clear the
1517 // certificate stats cache.
1518 fake_clock.AdvanceTime(TimeDelta::Seconds(1));
1519 rtc::scoped_refptr<const RTCStatsReport> second_report =
1520 stats_->GetStatsReport();
1521 // We expect to see the same certificates as before due to not clearing the
1522 // certificate cache.
1523 const auto* second_local_cert0 =
1524 second_report->GetAs<RTCCertificateStats>(first_local_cert0->id());
1525 const auto* second_local_cert1 =
1526 second_report->GetAs<RTCCertificateStats>(first_local_cert1->id());
1527 const auto* second_remote_cert0 =
1528 second_report->GetAs<RTCCertificateStats>(first_remote_cert0->id());
1529 const auto* second_remote_cert1 =
1530 second_report->GetAs<RTCCertificateStats>(first_remote_cert1->id());
1531 ASSERT_TRUE(second_local_cert0);
1532 ASSERT_TRUE(second_local_cert1);
1533 ASSERT_TRUE(second_remote_cert0);
1534 ASSERT_TRUE(second_remote_cert1);
1535 // The information in the certificate stats are obsolete.
1536 EXPECT_EQ(*second_local_cert0->fingerprint,
1537 initial_local_certinfo->fingerprints[0]);
1538 EXPECT_EQ(*second_local_cert1->fingerprint,
1539 initial_local_certinfo->fingerprints[1]);
1540 EXPECT_EQ(*second_remote_cert0->fingerprint,
1541 initial_remote_certinfo->fingerprints[0]);
1542 EXPECT_EQ(*second_remote_cert1->fingerprint,
1543 initial_remote_certinfo->fingerprints[1]);
1544 // But timestamps are up-to-date, because this is a fresh stats report.
Philipp Hanckeb81823a2023-01-04 14:17:421545 EXPECT_EQ(second_local_cert0->timestamp().us(), rtc::TimeMicros());
1546 EXPECT_EQ(second_local_cert1->timestamp().us(), rtc::TimeMicros());
1547 EXPECT_EQ(second_remote_cert0->timestamp().us(), rtc::TimeMicros());
1548 EXPECT_EQ(second_remote_cert1->timestamp().us(), rtc::TimeMicros());
Henrik Boström69d23c92022-09-26 12:13:171549 // The updated certificates are not part of the report yet.
1550 EXPECT_FALSE(GetCertificateStatsFromFingerprint(
1551 second_report, updated_local_certinfo->fingerprints[0]));
1552 EXPECT_FALSE(GetCertificateStatsFromFingerprint(
1553 second_report, updated_local_certinfo->fingerprints[1]));
1554 EXPECT_FALSE(GetCertificateStatsFromFingerprint(
1555 second_report, updated_remote_certinfo->fingerprints[0]));
1556 EXPECT_FALSE(GetCertificateStatsFromFingerprint(
1557 second_report, updated_remote_certinfo->fingerprints[1]));
1558
1559 // Clear the cache, including the cached certificates.
1560 stats_->stats_collector()->ClearCachedStatsReport();
1561 rtc::scoped_refptr<const RTCStatsReport> third_report =
1562 stats_->GetStatsReport();
1563 // Now the old certificates stats should be deleted.
1564 EXPECT_FALSE(third_report->Get(first_local_cert0->id()));
1565 EXPECT_FALSE(third_report->Get(first_local_cert1->id()));
1566 EXPECT_FALSE(third_report->Get(first_remote_cert0->id()));
1567 EXPECT_FALSE(third_report->Get(first_remote_cert1->id()));
1568 // And updated certificates exist.
1569 EXPECT_TRUE(GetCertificateStatsFromFingerprint(
1570 third_report, updated_local_certinfo->fingerprints[0]));
1571 EXPECT_TRUE(GetCertificateStatsFromFingerprint(
1572 third_report, updated_local_certinfo->fingerprints[1]));
1573 EXPECT_TRUE(GetCertificateStatsFromFingerprint(
1574 third_report, updated_remote_certinfo->fingerprints[0]));
1575 EXPECT_TRUE(GetCertificateStatsFromFingerprint(
1576 third_report, updated_remote_certinfo->fingerprints[1]));
1577}
1578
Harald Alvestrand928e7a32019-07-31 11:16:451579TEST_F(RTCStatsCollectorTest, CollectTwoRTCDataChannelStatsWithPendingId) {
Niels Möllere7cc8832022-01-04 14:20:031580 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
1581 /*id=*/-1, DataChannelInterface::kConnecting));
1582 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
1583 /*id=*/-1, DataChannelInterface::kConnecting));
Harald Alvestrand928e7a32019-07-31 11:16:451584
1585 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1586}
1587
hboscc555c52016-10-18 19:48:311588TEST_F(RTCStatsCollectorTest, CollectRTCDataChannelStats) {
Harald Alvestrand928e7a32019-07-31 11:16:451589 // Note: The test assumes data channel IDs are predictable.
1590 // This is not a safe assumption, but in order to make it work for
1591 // the test, we reset the ID allocator at test start.
Taylor Brandstetter3a034e12020-07-09 22:32:341592 SctpDataChannel::ResetInternalIdAllocatorForTesting(-1);
Niels Möllere7cc8832022-01-04 14:20:031593 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
Taylor Brandstetter3a034e12020-07-09 22:32:341594 0, "MockSctpDataChannel0", DataChannelInterface::kConnecting, "udp", 1, 2,
1595 3, 4));
Philipp Hanckeb81823a2023-01-04 14:17:421596 RTCDataChannelStats expected_data_channel0("D0", Timestamp::Zero());
Taylor Brandstetter3a034e12020-07-09 22:32:341597 expected_data_channel0.label = "MockSctpDataChannel0";
hbosdbb64d82016-12-21 09:57:461598 expected_data_channel0.protocol = "udp";
Harald Alvestrand10ef8472020-06-05 13:38:511599 expected_data_channel0.data_channel_identifier = 0;
hbosdbb64d82016-12-21 09:57:461600 expected_data_channel0.state = "connecting";
1601 expected_data_channel0.messages_sent = 1;
1602 expected_data_channel0.bytes_sent = 2;
1603 expected_data_channel0.messages_received = 3;
1604 expected_data_channel0.bytes_received = 4;
1605
Niels Möllere7cc8832022-01-04 14:20:031606 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
1607 1, "MockSctpDataChannel1", DataChannelInterface::kOpen, "tcp", 5, 6, 7,
1608 8));
Philipp Hanckeb81823a2023-01-04 14:17:421609 RTCDataChannelStats expected_data_channel1("D1", Timestamp::Zero());
Taylor Brandstetter3a034e12020-07-09 22:32:341610 expected_data_channel1.label = "MockSctpDataChannel1";
hbosdbb64d82016-12-21 09:57:461611 expected_data_channel1.protocol = "tcp";
Harald Alvestrand10ef8472020-06-05 13:38:511612 expected_data_channel1.data_channel_identifier = 1;
hbosdbb64d82016-12-21 09:57:461613 expected_data_channel1.state = "open";
1614 expected_data_channel1.messages_sent = 5;
1615 expected_data_channel1.bytes_sent = 6;
1616 expected_data_channel1.messages_received = 7;
1617 expected_data_channel1.bytes_received = 8;
1618
Niels Möllere7cc8832022-01-04 14:20:031619 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
Taylor Brandstetter3a034e12020-07-09 22:32:341620 2, "MockSctpDataChannel2", DataChannelInterface::kClosing, "udp", 9, 10,
1621 11, 12));
Philipp Hanckeb81823a2023-01-04 14:17:421622 RTCDataChannelStats expected_data_channel2("D2", Timestamp::Zero());
Taylor Brandstetter3a034e12020-07-09 22:32:341623 expected_data_channel2.label = "MockSctpDataChannel2";
hbosdbb64d82016-12-21 09:57:461624 expected_data_channel2.protocol = "udp";
Harald Alvestrand10ef8472020-06-05 13:38:511625 expected_data_channel2.data_channel_identifier = 2;
hbosdbb64d82016-12-21 09:57:461626 expected_data_channel2.state = "closing";
1627 expected_data_channel2.messages_sent = 9;
1628 expected_data_channel2.bytes_sent = 10;
1629 expected_data_channel2.messages_received = 11;
1630 expected_data_channel2.bytes_received = 12;
1631
Niels Möllere7cc8832022-01-04 14:20:031632 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
1633 3, "MockSctpDataChannel3", DataChannelInterface::kClosed, "tcp", 13, 14,
1634 15, 16));
Philipp Hanckeb81823a2023-01-04 14:17:421635 RTCDataChannelStats expected_data_channel3("D3", Timestamp::Zero());
Taylor Brandstetter3a034e12020-07-09 22:32:341636 expected_data_channel3.label = "MockSctpDataChannel3";
hbosdbb64d82016-12-21 09:57:461637 expected_data_channel3.protocol = "tcp";
Harald Alvestrand10ef8472020-06-05 13:38:511638 expected_data_channel3.data_channel_identifier = 3;
hbosdbb64d82016-12-21 09:57:461639 expected_data_channel3.state = "closed";
1640 expected_data_channel3.messages_sent = 13;
1641 expected_data_channel3.bytes_sent = 14;
1642 expected_data_channel3.messages_received = 15;
1643 expected_data_channel3.bytes_received = 16;
hboscc555c52016-10-18 19:48:311644
Steve Anton5b387312018-02-03 00:00:201645 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1646
hbosdbb64d82016-12-21 09:57:461647 ASSERT_TRUE(report->Get(expected_data_channel0.id()));
Yves Gerey665174f2018-06-19 13:03:051648 EXPECT_EQ(
1649 expected_data_channel0,
1650 report->Get(expected_data_channel0.id())->cast_to<RTCDataChannelStats>());
hbosdbb64d82016-12-21 09:57:461651 ASSERT_TRUE(report->Get(expected_data_channel1.id()));
Yves Gerey665174f2018-06-19 13:03:051652 EXPECT_EQ(
1653 expected_data_channel1,
1654 report->Get(expected_data_channel1.id())->cast_to<RTCDataChannelStats>());
hbosdbb64d82016-12-21 09:57:461655 ASSERT_TRUE(report->Get(expected_data_channel2.id()));
Yves Gerey665174f2018-06-19 13:03:051656 EXPECT_EQ(
1657 expected_data_channel2,
1658 report->Get(expected_data_channel2.id())->cast_to<RTCDataChannelStats>());
hbosdbb64d82016-12-21 09:57:461659 ASSERT_TRUE(report->Get(expected_data_channel3.id()));
Yves Gerey665174f2018-06-19 13:03:051660 EXPECT_EQ(
1661 expected_data_channel3,
1662 report->Get(expected_data_channel3.id())->cast_to<RTCDataChannelStats>());
hboscc555c52016-10-18 19:48:311663}
1664
hbosab9f6e42016-10-07 09:18:471665TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidateStats) {
1666 // Candidates in the first transport stats.
Jonas Oreland0d13bbd2022-03-02 10:17:361667 std::unique_ptr<cricket::Candidate> a_local_host = CreateFakeCandidate(
1668 "1.2.3.4", 5, "a_local_host's protocol", rtc::ADAPTER_TYPE_VPN,
1669 cricket::LOCAL_PORT_TYPE, 0, rtc::ADAPTER_TYPE_ETHERNET);
Philipp Hanckeb81823a2023-01-04 14:17:421670 RTCLocalIceCandidateStats expected_a_local_host("I" + a_local_host->id(),
1671 Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291672 expected_a_local_host.transport_id = "Ta0";
Gary Liu37e489c2017-11-21 18:49:361673 expected_a_local_host.network_type = "vpn";
hbosc42ba322016-12-21 11:31:451674 expected_a_local_host.ip = "1.2.3.4";
Philipp Hanckea9ba4502021-03-22 12:22:541675 expected_a_local_host.address = "1.2.3.4";
hbosc42ba322016-12-21 11:31:451676 expected_a_local_host.port = 5;
1677 expected_a_local_host.protocol = "a_local_host's protocol";
1678 expected_a_local_host.candidate_type = "host";
1679 expected_a_local_host.priority = 0;
Jonas Oreland0d13bbd2022-03-02 10:17:361680 expected_a_local_host.vpn = true;
1681 expected_a_local_host.network_adapter_type = RTCNetworkAdapterType::kEthernet;
Philipp Hancke0e3cd632022-09-27 08:23:091682 expected_a_local_host.foundation = "foundationIsAString";
1683 expected_a_local_host.username_fragment = "iceusernamefragment";
hbosc42ba322016-12-21 11:31:451684
hbosab9f6e42016-10-07 09:18:471685 std::unique_ptr<cricket::Candidate> a_remote_srflx = CreateFakeCandidate(
Gary Liu37e489c2017-11-21 18:49:361686 "6.7.8.9", 10, "remote_srflx's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
1687 cricket::STUN_PORT_TYPE, 1);
Henrik Boström8dfc90f2022-09-02 07:39:291688 RTCRemoteIceCandidateStats expected_a_remote_srflx("I" + a_remote_srflx->id(),
Philipp Hanckeb81823a2023-01-04 14:17:421689 Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291690 expected_a_remote_srflx.transport_id = "Ta0";
hbosc42ba322016-12-21 11:31:451691 expected_a_remote_srflx.ip = "6.7.8.9";
Philipp Hanckea9ba4502021-03-22 12:22:541692 expected_a_remote_srflx.address = "6.7.8.9";
hbosc42ba322016-12-21 11:31:451693 expected_a_remote_srflx.port = 10;
1694 expected_a_remote_srflx.protocol = "remote_srflx's protocol";
1695 expected_a_remote_srflx.candidate_type = "srflx";
1696 expected_a_remote_srflx.priority = 1;
Philipp Hancke0e3cd632022-09-27 08:23:091697 expected_a_remote_srflx.foundation = "foundationIsAString";
1698 expected_a_remote_srflx.username_fragment = "iceusernamefragment";
hbosc42ba322016-12-21 11:31:451699
hbosab9f6e42016-10-07 09:18:471700 std::unique_ptr<cricket::Candidate> a_local_prflx = CreateFakeCandidate(
Jonas Oreland0d13bbd2022-03-02 10:17:361701 "11.12.13.14", 15, "a_local_prflx's protocol",
1702 rtc::ADAPTER_TYPE_CELLULAR_2G, cricket::PRFLX_PORT_TYPE, 2);
Henrik Boström8dfc90f2022-09-02 07:39:291703 RTCLocalIceCandidateStats expected_a_local_prflx("I" + a_local_prflx->id(),
Philipp Hanckeb81823a2023-01-04 14:17:421704 Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291705 expected_a_local_prflx.transport_id = "Ta0";
Gary Liu37e489c2017-11-21 18:49:361706 expected_a_local_prflx.network_type = "cellular";
hbosc42ba322016-12-21 11:31:451707 expected_a_local_prflx.ip = "11.12.13.14";
Philipp Hanckea9ba4502021-03-22 12:22:541708 expected_a_local_prflx.address = "11.12.13.14";
hbosc42ba322016-12-21 11:31:451709 expected_a_local_prflx.port = 15;
1710 expected_a_local_prflx.protocol = "a_local_prflx's protocol";
1711 expected_a_local_prflx.candidate_type = "prflx";
1712 expected_a_local_prflx.priority = 2;
Jonas Oreland0d13bbd2022-03-02 10:17:361713 expected_a_local_prflx.vpn = false;
1714 expected_a_local_prflx.network_adapter_type =
1715 RTCNetworkAdapterType::kCellular2g;
Philipp Hancke0e3cd632022-09-27 08:23:091716 expected_a_local_prflx.foundation = "foundationIsAString";
1717 expected_a_local_prflx.username_fragment = "iceusernamefragment";
hbosc42ba322016-12-21 11:31:451718
hbosab9f6e42016-10-07 09:18:471719 std::unique_ptr<cricket::Candidate> a_remote_relay = CreateFakeCandidate(
Gary Liu37e489c2017-11-21 18:49:361720 "16.17.18.19", 20, "a_remote_relay's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
1721 cricket::RELAY_PORT_TYPE, 3);
Henrik Boström8dfc90f2022-09-02 07:39:291722 RTCRemoteIceCandidateStats expected_a_remote_relay("I" + a_remote_relay->id(),
Philipp Hanckeb81823a2023-01-04 14:17:421723 Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291724 expected_a_remote_relay.transport_id = "Ta0";
hbosc42ba322016-12-21 11:31:451725 expected_a_remote_relay.ip = "16.17.18.19";
Philipp Hanckea9ba4502021-03-22 12:22:541726 expected_a_remote_relay.address = "16.17.18.19";
hbosc42ba322016-12-21 11:31:451727 expected_a_remote_relay.port = 20;
1728 expected_a_remote_relay.protocol = "a_remote_relay's protocol";
1729 expected_a_remote_relay.candidate_type = "relay";
1730 expected_a_remote_relay.priority = 3;
Philipp Hancke0e3cd632022-09-27 08:23:091731 expected_a_remote_relay.foundation = "foundationIsAString";
1732 expected_a_remote_relay.username_fragment = "iceusernamefragment";
hbosc42ba322016-12-21 11:31:451733
Philipp Hancke95513752018-09-27 12:40:081734 std::unique_ptr<cricket::Candidate> a_local_relay = CreateFakeCandidate(
1735 "16.17.18.19", 21, "a_local_relay's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
1736 cricket::RELAY_PORT_TYPE, 1);
1737 a_local_relay->set_relay_protocol("tcp");
Philipp Hancke05b29c72022-02-02 11:06:151738 a_local_relay->set_url("turn:url1");
Philipp Hancke95513752018-09-27 12:40:081739
Henrik Boström8dfc90f2022-09-02 07:39:291740 RTCLocalIceCandidateStats expected_a_local_relay("I" + a_local_relay->id(),
Philipp Hanckeb81823a2023-01-04 14:17:421741 Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291742 expected_a_local_relay.transport_id = "Ta0";
Philipp Hanckefbd52c02021-11-10 22:02:171743 expected_a_local_relay.network_type = "unknown";
Philipp Hancke95513752018-09-27 12:40:081744 expected_a_local_relay.ip = "16.17.18.19";
Philipp Hanckea9ba4502021-03-22 12:22:541745 expected_a_local_relay.address = "16.17.18.19";
Philipp Hancke95513752018-09-27 12:40:081746 expected_a_local_relay.port = 21;
1747 expected_a_local_relay.protocol = "a_local_relay's protocol";
1748 expected_a_local_relay.relay_protocol = "tcp";
1749 expected_a_local_relay.candidate_type = "relay";
1750 expected_a_local_relay.priority = 1;
Philipp Hancke05b29c72022-02-02 11:06:151751 expected_a_local_relay.url = "turn:url1";
Jonas Oreland0d13bbd2022-03-02 10:17:361752 expected_a_local_relay.vpn = false;
1753 expected_a_local_relay.network_adapter_type = RTCNetworkAdapterType::kUnknown;
Philipp Hancke0e3cd632022-09-27 08:23:091754 expected_a_local_relay.foundation = "foundationIsAString";
1755 expected_a_local_relay.username_fragment = "iceusernamefragment";
Philipp Hancke95513752018-09-27 12:40:081756
Philipp Hancke21c4b1e2021-11-11 06:45:591757 std::unique_ptr<cricket::Candidate> a_local_relay_prflx = CreateFakeCandidate(
1758 "11.12.13.20", 22, "a_local_relay_prflx's protocol",
1759 rtc::ADAPTER_TYPE_UNKNOWN, cricket::PRFLX_PORT_TYPE, 1);
1760 a_local_relay_prflx->set_relay_protocol("udp");
1761
1762 RTCLocalIceCandidateStats expected_a_local_relay_prflx(
Philipp Hanckeb81823a2023-01-04 14:17:421763 "I" + a_local_relay_prflx->id(), Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291764 expected_a_local_relay_prflx.transport_id = "Ta0";
Philipp Hancke21c4b1e2021-11-11 06:45:591765 expected_a_local_relay_prflx.network_type = "unknown";
1766 expected_a_local_relay_prflx.ip = "11.12.13.20";
1767 expected_a_local_relay_prflx.address = "11.12.13.20";
1768 expected_a_local_relay_prflx.port = 22;
1769 expected_a_local_relay_prflx.protocol = "a_local_relay_prflx's protocol";
1770 expected_a_local_relay_prflx.relay_protocol = "udp";
1771 expected_a_local_relay_prflx.candidate_type = "prflx";
1772 expected_a_local_relay_prflx.priority = 1;
Jonas Oreland0d13bbd2022-03-02 10:17:361773 expected_a_local_relay_prflx.vpn = false;
1774 expected_a_local_relay_prflx.network_adapter_type =
1775 RTCNetworkAdapterType::kUnknown;
Philipp Hancke0e3cd632022-09-27 08:23:091776 expected_a_local_relay_prflx.foundation = "foundationIsAString";
1777 expected_a_local_relay_prflx.username_fragment = "iceusernamefragment";
Philipp Hancke21c4b1e2021-11-11 06:45:591778
Philipp Hancke6e57ca22022-06-09 13:58:181779 // A non-paired local candidate.
1780 std::unique_ptr<cricket::Candidate> a_local_host_not_paired =
1781 CreateFakeCandidate("1.2.3.4", 4404, "a_local_host_not_paired's protocol",
1782 rtc::ADAPTER_TYPE_VPN, cricket::LOCAL_PORT_TYPE, 0,
1783 rtc::ADAPTER_TYPE_ETHERNET);
1784 RTCLocalIceCandidateStats expected_a_local_host_not_paired(
Philipp Hanckeb81823a2023-01-04 14:17:421785 "I" + a_local_host_not_paired->id(), Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291786 expected_a_local_host_not_paired.transport_id = "Ta0";
Philipp Hancke6e57ca22022-06-09 13:58:181787 expected_a_local_host_not_paired.network_type = "vpn";
1788 expected_a_local_host_not_paired.ip = "1.2.3.4";
1789 expected_a_local_host_not_paired.address = "1.2.3.4";
1790 expected_a_local_host_not_paired.port = 4404;
1791 expected_a_local_host_not_paired.protocol =
1792 "a_local_host_not_paired's protocol";
1793 expected_a_local_host_not_paired.candidate_type = "host";
1794 expected_a_local_host_not_paired.priority = 0;
1795 expected_a_local_host_not_paired.vpn = true;
1796 expected_a_local_host_not_paired.network_adapter_type =
1797 RTCNetworkAdapterType::kEthernet;
Philipp Hancke0e3cd632022-09-27 08:23:091798 expected_a_local_host_not_paired.foundation = "foundationIsAString";
1799 expected_a_local_host_not_paired.username_fragment = "iceusernamefragment";
Philipp Hancke6e57ca22022-06-09 13:58:181800
hbosab9f6e42016-10-07 09:18:471801 // Candidates in the second transport stats.
Gary Liu37e489c2017-11-21 18:49:361802 std::unique_ptr<cricket::Candidate> b_local =
1803 CreateFakeCandidate("42.42.42.42", 42, "b_local's protocol",
1804 rtc::ADAPTER_TYPE_WIFI, cricket::LOCAL_PORT_TYPE, 42);
Philipp Hanckeb81823a2023-01-04 14:17:421805 RTCLocalIceCandidateStats expected_b_local("I" + b_local->id(),
1806 Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291807 expected_b_local.transport_id = "Tb0";
Gary Liu37e489c2017-11-21 18:49:361808 expected_b_local.network_type = "wifi";
hbosc42ba322016-12-21 11:31:451809 expected_b_local.ip = "42.42.42.42";
Philipp Hanckea9ba4502021-03-22 12:22:541810 expected_b_local.address = "42.42.42.42";
hbosc42ba322016-12-21 11:31:451811 expected_b_local.port = 42;
1812 expected_b_local.protocol = "b_local's protocol";
1813 expected_b_local.candidate_type = "host";
1814 expected_b_local.priority = 42;
Jonas Oreland0d13bbd2022-03-02 10:17:361815 expected_b_local.vpn = false;
1816 expected_b_local.network_adapter_type = RTCNetworkAdapterType::kWifi;
Philipp Hancke0e3cd632022-09-27 08:23:091817 expected_b_local.foundation = "foundationIsAString";
1818 expected_b_local.username_fragment = "iceusernamefragment";
hbosc42ba322016-12-21 11:31:451819
hbosab9f6e42016-10-07 09:18:471820 std::unique_ptr<cricket::Candidate> b_remote = CreateFakeCandidate(
Gary Liu37e489c2017-11-21 18:49:361821 "42.42.42.42", 42, "b_remote's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
1822 cricket::LOCAL_PORT_TYPE, 42);
Philipp Hanckeb81823a2023-01-04 14:17:421823 RTCRemoteIceCandidateStats expected_b_remote("I" + b_remote->id(),
1824 Timestamp::Zero());
Henrik Boström8dfc90f2022-09-02 07:39:291825 expected_b_remote.transport_id = "Tb0";
hbosc42ba322016-12-21 11:31:451826 expected_b_remote.ip = "42.42.42.42";
Philipp Hanckea9ba4502021-03-22 12:22:541827 expected_b_remote.address = "42.42.42.42";
hbosc42ba322016-12-21 11:31:451828 expected_b_remote.port = 42;
1829 expected_b_remote.protocol = "b_remote's protocol";
1830 expected_b_remote.candidate_type = "host";
1831 expected_b_remote.priority = 42;
Philipp Hancke0e3cd632022-09-27 08:23:091832 expected_b_remote.foundation = "foundationIsAString";
1833 expected_b_remote.username_fragment = "iceusernamefragment";
hbosab9f6e42016-10-07 09:18:471834
Philipp Hancke95513752018-09-27 12:40:081835 // Add candidate pairs to connection.
hbosab9f6e42016-10-07 09:18:471836 cricket::TransportChannelStats a_transport_channel_stats;
Jonas Oreland149dc722019-08-28 06:10:271837 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[0]
1840 .local_candidate = *a_local_host.get();
1841 a_transport_channel_stats.ice_transport_stats.connection_infos[0]
1842 .remote_candidate = *a_remote_srflx.get();
1843 a_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
hbosab9f6e42016-10-07 09:18:471844 cricket::ConnectionInfo());
Jonas Oreland149dc722019-08-28 06:10:271845 a_transport_channel_stats.ice_transport_stats.connection_infos[1]
1846 .local_candidate = *a_local_prflx.get();
1847 a_transport_channel_stats.ice_transport_stats.connection_infos[1]
1848 .remote_candidate = *a_remote_relay.get();
1849 a_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
Philipp Hancke95513752018-09-27 12:40:081850 cricket::ConnectionInfo());
Jonas Oreland149dc722019-08-28 06:10:271851 a_transport_channel_stats.ice_transport_stats.connection_infos[2]
1852 .local_candidate = *a_local_relay.get();
1853 a_transport_channel_stats.ice_transport_stats.connection_infos[2]
1854 .remote_candidate = *a_remote_relay.get();
Philipp Hancke21c4b1e2021-11-11 06:45:591855 a_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
1856 cricket::ConnectionInfo());
1857 a_transport_channel_stats.ice_transport_stats.connection_infos[3]
1858 .local_candidate = *a_local_relay_prflx.get();
1859 a_transport_channel_stats.ice_transport_stats.connection_infos[3]
1860 .remote_candidate = *a_remote_relay.get();
Philipp Hancke6e57ca22022-06-09 13:58:181861 a_transport_channel_stats.ice_transport_stats.candidate_stats_list.push_back(
1862 cricket::CandidateStats(*a_local_host_not_paired.get()));
Steve Anton5b387312018-02-03 00:00:201863
1864 pc_->AddVoiceChannel("audio", "a");
1865 pc_->SetTransportStats("a", a_transport_channel_stats);
hbosab9f6e42016-10-07 09:18:471866
1867 cricket::TransportChannelStats b_transport_channel_stats;
Jonas Oreland149dc722019-08-28 06:10:271868 b_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
hbosab9f6e42016-10-07 09:18:471869 cricket::ConnectionInfo());
Jonas Oreland149dc722019-08-28 06:10:271870 b_transport_channel_stats.ice_transport_stats.connection_infos[0]
1871 .local_candidate = *b_local.get();
1872 b_transport_channel_stats.ice_transport_stats.connection_infos[0]
1873 .remote_candidate = *b_remote.get();
hbosab9f6e42016-10-07 09:18:471874
Steve Anton5b387312018-02-03 00:00:201875 pc_->AddVideoChannel("video", "b");
1876 pc_->SetTransportStats("b", b_transport_channel_stats);
hbosab9f6e42016-10-07 09:18:471877
Steve Anton5b387312018-02-03 00:00:201878 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbosc42ba322016-12-21 11:31:451879
hbosb4e426e2017-01-02 17:59:311880 ASSERT_TRUE(report->Get(expected_a_local_host.id()));
Yves Gerey665174f2018-06-19 13:03:051881 EXPECT_EQ(expected_a_local_host, report->Get(expected_a_local_host.id())
1882 ->cast_to<RTCLocalIceCandidateStats>());
Philipp Hancke6e57ca22022-06-09 13:58:181883
1884 ASSERT_TRUE(report->Get(expected_a_local_host_not_paired.id()));
1885 EXPECT_EQ(expected_a_local_host_not_paired,
1886 report->Get(expected_a_local_host_not_paired.id())
1887 ->cast_to<RTCLocalIceCandidateStats>());
1888
hbosb4e426e2017-01-02 17:59:311889 ASSERT_TRUE(report->Get(expected_a_remote_srflx.id()));
hbosc42ba322016-12-21 11:31:451890 EXPECT_EQ(expected_a_remote_srflx,
Yves Gerey665174f2018-06-19 13:03:051891 report->Get(expected_a_remote_srflx.id())
1892 ->cast_to<RTCRemoteIceCandidateStats>());
hbosb4e426e2017-01-02 17:59:311893 ASSERT_TRUE(report->Get(expected_a_local_prflx.id()));
Yves Gerey665174f2018-06-19 13:03:051894 EXPECT_EQ(expected_a_local_prflx, report->Get(expected_a_local_prflx.id())
1895 ->cast_to<RTCLocalIceCandidateStats>());
hbosb4e426e2017-01-02 17:59:311896 ASSERT_TRUE(report->Get(expected_a_remote_relay.id()));
hbosc42ba322016-12-21 11:31:451897 EXPECT_EQ(expected_a_remote_relay,
Yves Gerey665174f2018-06-19 13:03:051898 report->Get(expected_a_remote_relay.id())
1899 ->cast_to<RTCRemoteIceCandidateStats>());
Philipp Hanckefbd52c02021-11-10 22:02:171900 ASSERT_TRUE(report->Get(expected_a_local_relay.id()));
1901 EXPECT_EQ(expected_a_local_relay, report->Get(expected_a_local_relay.id())
1902 ->cast_to<RTCLocalIceCandidateStats>());
Philipp Hancke21c4b1e2021-11-11 06:45:591903 ASSERT_TRUE(report->Get(expected_a_local_relay_prflx.id()));
1904 EXPECT_EQ(expected_a_local_relay_prflx,
1905 report->Get(expected_a_local_relay_prflx.id())
1906 ->cast_to<RTCLocalIceCandidateStats>());
hbosb4e426e2017-01-02 17:59:311907 ASSERT_TRUE(report->Get(expected_b_local.id()));
Yves Gerey665174f2018-06-19 13:03:051908 EXPECT_EQ(
1909 expected_b_local,
1910 report->Get(expected_b_local.id())->cast_to<RTCLocalIceCandidateStats>());
hbosb4e426e2017-01-02 17:59:311911 ASSERT_TRUE(report->Get(expected_b_remote.id()));
Yves Gerey665174f2018-06-19 13:03:051912 EXPECT_EQ(expected_b_remote, report->Get(expected_b_remote.id())
1913 ->cast_to<RTCRemoteIceCandidateStats>());
Henrik Boström8dfc90f2022-09-02 07:39:291914 EXPECT_TRUE(report->Get("Ta0"));
1915 EXPECT_TRUE(report->Get("Tb0"));
hbosab9f6e42016-10-07 09:18:471916}
1917
hbosc47a0c32016-10-11 21:54:491918TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidatePairStats) {
Steve Anton5b387312018-02-03 00:00:201919 const char kTransportName[] = "transport";
hbos338f78a2017-02-07 14:41:211920
Gary Liu37e489c2017-11-21 18:49:361921 std::unique_ptr<cricket::Candidate> local_candidate =
1922 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
1923 cricket::LOCAL_PORT_TYPE, 42);
Philipp Hancke0e3cd632022-09-27 08:23:091924 local_candidate->set_username("local_iceusernamefragment");
1925
hbosc47a0c32016-10-11 21:54:491926 std::unique_ptr<cricket::Candidate> remote_candidate = CreateFakeCandidate(
Gary Liu37e489c2017-11-21 18:49:361927 "42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_UNKNOWN,
Philipp Hancke0e3cd632022-09-27 08:23:091928 cricket::STUN_PORT_TYPE, 42);
1929 remote_candidate->set_related_address(rtc::SocketAddress("192.168.2.1", 43));
1930 remote_candidate->set_username("remote_iceusernamefragment");
hbosc47a0c32016-10-11 21:54:491931
hbosc47a0c32016-10-11 21:54:491932 cricket::ConnectionInfo connection_info;
hbos338f78a2017-02-07 14:41:211933 connection_info.best_connection = false;
hbosc47a0c32016-10-11 21:54:491934 connection_info.local_candidate = *local_candidate.get();
1935 connection_info.remote_candidate = *remote_candidate.get();
1936 connection_info.writable = true;
Taylor Brandstetter79326ea2021-09-28 22:09:531937 connection_info.sent_discarded_packets = 3;
1938 connection_info.sent_total_packets = 10;
1939 connection_info.packets_received = 51;
1940 connection_info.sent_discarded_bytes = 7;
hbosc47a0c32016-10-11 21:54:491941 connection_info.sent_total_bytes = 42;
1942 connection_info.recv_total_bytes = 1234;
hbosbf8d3e52017-02-28 14:34:471943 connection_info.total_round_trip_time_ms = 0;
Danil Chapovalov66cadcc2018-06-19 14:47:431944 connection_info.current_round_trip_time_ms = absl::nullopt;
hbosd82f5122016-12-09 12:12:391945 connection_info.recv_ping_requests = 2020;
Henrik Boström839439a2022-09-06 09:16:361946 connection_info.sent_ping_requests_total = 2222;
hbose448dd52016-12-12 09:22:531947 connection_info.sent_ping_requests_before_first_response = 2000;
hbosc47a0c32016-10-11 21:54:491948 connection_info.recv_ping_responses = 4321;
1949 connection_info.sent_ping_responses = 1000;
hbos06495bc2017-01-02 16:08:181950 connection_info.state = cricket::IceCandidatePairState::IN_PROGRESS;
1951 connection_info.priority = 5555;
hbos92eaec62017-02-27 09:38:081952 connection_info.nominated = false;
Philipp Hancke0487c572022-11-01 16:03:011953 connection_info.last_data_received = Timestamp::Millis(2500);
1954 connection_info.last_data_sent = Timestamp::Millis(5200);
hbosc47a0c32016-10-11 21:54:491955
1956 cricket::TransportChannelStats transport_channel_stats;
hbos0583b282016-11-30 09:50:141957 transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
Jonas Oreland149dc722019-08-28 06:10:271958 transport_channel_stats.ice_transport_stats.connection_infos.push_back(
1959 connection_info);
hbosc47a0c32016-10-11 21:54:491960
Steve Anton5b387312018-02-03 00:00:201961 pc_->AddVideoChannel("video", kTransportName);
1962 pc_->SetTransportStats(kTransportName, transport_channel_stats);
hbosc47a0c32016-10-11 21:54:491963
Steve Anton5b387312018-02-03 00:00:201964 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos0583b282016-11-30 09:50:141965
Henrik Boström8dfc90f2022-09-02 07:39:291966 RTCIceCandidatePairStats expected_pair(
1967 "CP" + local_candidate->id() + "_" + remote_candidate->id(),
Philipp Hanckeb81823a2023-01-04 14:17:421968 report->timestamp());
hbos0583b282016-11-30 09:50:141969 expected_pair.transport_id =
Henrik Boström8dfc90f2022-09-02 07:39:291970 "Ttransport" + rtc::ToString(cricket::ICE_CANDIDATE_COMPONENT_RTP);
1971 expected_pair.local_candidate_id = "I" + local_candidate->id();
1972 expected_pair.remote_candidate_id = "I" + remote_candidate->id();
hbos06495bc2017-01-02 16:08:181973 expected_pair.state = RTCStatsIceCandidatePairState::kInProgress;
1974 expected_pair.priority = 5555;
hbos92eaec62017-02-27 09:38:081975 expected_pair.nominated = false;
hbos0583b282016-11-30 09:50:141976 expected_pair.writable = true;
Taylor Brandstetter79326ea2021-09-28 22:09:531977 expected_pair.packets_sent = 7;
1978 expected_pair.packets_received = 51;
1979 expected_pair.packets_discarded_on_send = 3;
hbos0583b282016-11-30 09:50:141980 expected_pair.bytes_sent = 42;
1981 expected_pair.bytes_received = 1234;
Taylor Brandstetter79326ea2021-09-28 22:09:531982 expected_pair.bytes_discarded_on_send = 7;
hbosbf8d3e52017-02-28 14:34:471983 expected_pair.total_round_trip_time = 0.0;
hbosd82f5122016-12-09 12:12:391984 expected_pair.requests_received = 2020;
Henrik Boström839439a2022-09-06 09:16:361985 expected_pair.requests_sent = 2222;
hbos0583b282016-11-30 09:50:141986 expected_pair.responses_received = 4321;
1987 expected_pair.responses_sent = 1000;
Henrik Boström839439a2022-09-06 09:16:361988 expected_pair.consent_requests_sent = (2222 - 2000);
Philipp Hancke0487c572022-11-01 16:03:011989 expected_pair.last_packet_received_timestamp = 2500;
1990 expected_pair.last_packet_sent_timestamp = 5200;
1991
Artem Titovcfea2182021-08-09 23:22:311992 // `expected_pair.current_round_trip_time` should be undefined because the
hbosbf8d3e52017-02-28 14:34:471993 // current RTT is not set.
Artem Titovcfea2182021-08-09 23:22:311994 // `expected_pair.available_[outgoing/incoming]_bitrate` should be undefined
hbos338f78a2017-02-07 14:41:211995 // because is is not the current pair.
hbos0583b282016-11-30 09:50:141996
hbosdbb64d82016-12-21 09:57:461997 ASSERT_TRUE(report->Get(expected_pair.id()));
hbos0583b282016-11-30 09:50:141998 EXPECT_EQ(
1999 expected_pair,
2000 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
hbosb4e426e2017-01-02 17:59:312001 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
hbos0583b282016-11-30 09:50:142002
hbos92eaec62017-02-27 09:38:082003 // Set nominated and "GetStats" again.
Jonas Oreland149dc722019-08-28 06:10:272004 transport_channel_stats.ice_transport_stats.connection_infos[0].nominated =
2005 true;
Steve Anton5b387312018-02-03 00:00:202006 pc_->SetTransportStats(kTransportName, transport_channel_stats);
2007 report = stats_->GetFreshStatsReport();
hbos92eaec62017-02-27 09:38:082008 expected_pair.nominated = true;
2009 ASSERT_TRUE(report->Get(expected_pair.id()));
2010 EXPECT_EQ(
2011 expected_pair,
2012 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
2013 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
2014
hbosbf8d3e52017-02-28 14:34:472015 // Set round trip times and "GetStats" again.
Jonas Oreland149dc722019-08-28 06:10:272016 transport_channel_stats.ice_transport_stats.connection_infos[0]
2017 .total_round_trip_time_ms = 7331;
2018 transport_channel_stats.ice_transport_stats.connection_infos[0]
2019 .current_round_trip_time_ms = 1337;
Steve Anton5b387312018-02-03 00:00:202020 pc_->SetTransportStats(kTransportName, transport_channel_stats);
2021 report = stats_->GetFreshStatsReport();
hbosbf8d3e52017-02-28 14:34:472022 expected_pair.total_round_trip_time = 7.331;
2023 expected_pair.current_round_trip_time = 1.337;
2024 ASSERT_TRUE(report->Get(expected_pair.id()));
2025 EXPECT_EQ(
2026 expected_pair,
2027 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
2028 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
2029
hbos338f78a2017-02-07 14:41:212030 // Make pair the current pair, clear bandwidth and "GetStats" again.
Jonas Oreland149dc722019-08-28 06:10:272031 transport_channel_stats.ice_transport_stats.connection_infos[0]
2032 .best_connection = true;
Steve Anton5b387312018-02-03 00:00:202033 pc_->SetTransportStats(kTransportName, transport_channel_stats);
2034 report = stats_->GetFreshStatsReport();
hbos338f78a2017-02-07 14:41:212035 // |expected_pair.available_[outgoing/incoming]_bitrate| should still be
2036 // undefined because bandwidth is not set.
2037 ASSERT_TRUE(report->Get(expected_pair.id()));
2038 EXPECT_EQ(
2039 expected_pair,
2040 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
2041 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
2042
2043 // Set bandwidth and "GetStats" again.
stefanf79ade12017-06-02 13:44:032044 webrtc::Call::Stats call_stats;
2045 const int kSendBandwidth = 888;
2046 call_stats.send_bandwidth_bps = kSendBandwidth;
2047 const int kRecvBandwidth = 999;
2048 call_stats.recv_bandwidth_bps = kRecvBandwidth;
Steve Anton5b387312018-02-03 00:00:202049 pc_->SetCallStats(call_stats);
2050 report = stats_->GetFreshStatsReport();
stefanf79ade12017-06-02 13:44:032051 expected_pair.available_outgoing_bitrate = kSendBandwidth;
2052 expected_pair.available_incoming_bitrate = kRecvBandwidth;
hbos338f78a2017-02-07 14:41:212053 ASSERT_TRUE(report->Get(expected_pair.id()));
2054 EXPECT_EQ(
2055 expected_pair,
2056 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
2057 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
2058
hbosc42ba322016-12-21 11:31:452059 RTCLocalIceCandidateStats expected_local_candidate(
Philipp Hanckeb81823a2023-01-04 14:17:422060 *expected_pair.local_candidate_id, report->timestamp());
hbosb4e426e2017-01-02 17:59:312061 expected_local_candidate.transport_id = *expected_pair.transport_id;
Gary Liu37e489c2017-11-21 18:49:362062 expected_local_candidate.network_type = "wifi";
hbosc42ba322016-12-21 11:31:452063 expected_local_candidate.ip = "42.42.42.42";
Philipp Hanckea9ba4502021-03-22 12:22:542064 expected_local_candidate.address = "42.42.42.42";
hbosc42ba322016-12-21 11:31:452065 expected_local_candidate.port = 42;
2066 expected_local_candidate.protocol = "protocol";
2067 expected_local_candidate.candidate_type = "host";
2068 expected_local_candidate.priority = 42;
Philipp Hancke0e3cd632022-09-27 08:23:092069 expected_local_candidate.foundation = "foundationIsAString";
2070 expected_local_candidate.username_fragment = "local_iceusernamefragment";
Jonas Oreland0d13bbd2022-03-02 10:17:362071 expected_local_candidate.vpn = false;
2072 expected_local_candidate.network_adapter_type = RTCNetworkAdapterType::kWifi;
hbosc42ba322016-12-21 11:31:452073 ASSERT_TRUE(report->Get(expected_local_candidate.id()));
2074 EXPECT_EQ(expected_local_candidate,
Yves Gerey665174f2018-06-19 13:03:052075 report->Get(expected_local_candidate.id())
2076 ->cast_to<RTCLocalIceCandidateStats>());
hbosc42ba322016-12-21 11:31:452077
2078 RTCRemoteIceCandidateStats expected_remote_candidate(
Philipp Hanckeb81823a2023-01-04 14:17:422079 *expected_pair.remote_candidate_id, report->timestamp());
hbosb4e426e2017-01-02 17:59:312080 expected_remote_candidate.transport_id = *expected_pair.transport_id;
hbosc42ba322016-12-21 11:31:452081 expected_remote_candidate.ip = "42.42.42.42";
Philipp Hanckea9ba4502021-03-22 12:22:542082 expected_remote_candidate.address = "42.42.42.42";
hbosc42ba322016-12-21 11:31:452083 expected_remote_candidate.port = 42;
2084 expected_remote_candidate.protocol = "protocol";
Philipp Hancke0e3cd632022-09-27 08:23:092085 expected_remote_candidate.candidate_type = "srflx";
hbosc42ba322016-12-21 11:31:452086 expected_remote_candidate.priority = 42;
Philipp Hancke0e3cd632022-09-27 08:23:092087 expected_remote_candidate.foundation = "foundationIsAString";
2088 expected_remote_candidate.username_fragment = "remote_iceusernamefragment";
2089 expected_remote_candidate.related_address = "192.168.2.1";
2090 expected_remote_candidate.related_port = 43;
hbosc42ba322016-12-21 11:31:452091 ASSERT_TRUE(report->Get(expected_remote_candidate.id()));
2092 EXPECT_EQ(expected_remote_candidate,
Yves Gerey665174f2018-06-19 13:03:052093 report->Get(expected_remote_candidate.id())
2094 ->cast_to<RTCRemoteIceCandidateStats>());
hbosc47a0c32016-10-11 21:54:492095}
2096
hbosd565b732016-08-30 21:04:352097TEST_F(RTCStatsCollectorTest, CollectRTCPeerConnectionStats) {
hbosd565b732016-08-30 21:04:352098 {
Steve Anton5b387312018-02-03 00:00:202099 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Philipp Hanckeb81823a2023-01-04 14:17:422100 RTCPeerConnectionStats expected("P", report->timestamp());
hbos82ebe022016-11-14 09:41:092101 expected.data_channels_opened = 0;
2102 expected.data_channels_closed = 0;
Henrik Boström8dfc90f2022-09-02 07:39:292103 ASSERT_TRUE(report->Get("P"));
2104 EXPECT_EQ(expected, report->Get("P")->cast_to<RTCPeerConnectionStats>());
hbosd565b732016-08-30 21:04:352105 }
2106
Tomas Gunnarsson7d3cfbf2020-06-15 11:47:422107 // TODO(bugs.webrtc.org/11547): Supply a separate network thread.
Harald Alvestrand9e5aeb92022-05-11 09:35:362108 FakeDataChannelController controller;
Taylor Brandstetter3a034e12020-07-09 22:32:342109 rtc::scoped_refptr<SctpDataChannel> dummy_channel_a = SctpDataChannel::Create(
Harald Alvestrand9e5aeb92022-05-11 09:35:362110 &controller, "DummyChannelA", InternalDataChannelInit(),
Tomas Gunnarsson7d3cfbf2020-06-15 11:47:422111 rtc::Thread::Current(), rtc::Thread::Current());
Mirko Bonadeie0bc8d22022-02-08 07:41:252112 pc_->SignalSctpDataChannelCreated()(dummy_channel_a.get());
Taylor Brandstetter3a034e12020-07-09 22:32:342113 rtc::scoped_refptr<SctpDataChannel> dummy_channel_b = SctpDataChannel::Create(
Harald Alvestrand9e5aeb92022-05-11 09:35:362114 &controller, "DummyChannelB", InternalDataChannelInit(),
Tomas Gunnarsson7d3cfbf2020-06-15 11:47:422115 rtc::Thread::Current(), rtc::Thread::Current());
Mirko Bonadeie0bc8d22022-02-08 07:41:252116 pc_->SignalSctpDataChannelCreated()(dummy_channel_b.get());
hbosd565b732016-08-30 21:04:352117
hbos82ebe022016-11-14 09:41:092118 dummy_channel_a->SignalOpened(dummy_channel_a.get());
2119 // Closing a channel that is not opened should not affect the counts.
2120 dummy_channel_b->SignalClosed(dummy_channel_b.get());
2121
hbosd565b732016-08-30 21:04:352122 {
Steve Anton5b387312018-02-03 00:00:202123 rtc::scoped_refptr<const RTCStatsReport> report =
2124 stats_->GetFreshStatsReport();
Philipp Hanckeb81823a2023-01-04 14:17:422125 RTCPeerConnectionStats expected("P", report->timestamp());
hbos82ebe022016-11-14 09:41:092126 expected.data_channels_opened = 1;
2127 expected.data_channels_closed = 0;
Henrik Boström8dfc90f2022-09-02 07:39:292128 ASSERT_TRUE(report->Get("P"));
2129 EXPECT_EQ(expected, report->Get("P")->cast_to<RTCPeerConnectionStats>());
hbos82ebe022016-11-14 09:41:092130 }
2131
2132 dummy_channel_b->SignalOpened(dummy_channel_b.get());
2133 dummy_channel_b->SignalClosed(dummy_channel_b.get());
2134
2135 {
Steve Anton5b387312018-02-03 00:00:202136 rtc::scoped_refptr<const RTCStatsReport> report =
2137 stats_->GetFreshStatsReport();
Philipp Hanckeb81823a2023-01-04 14:17:422138 RTCPeerConnectionStats expected("P", report->timestamp());
hbos82ebe022016-11-14 09:41:092139 expected.data_channels_opened = 2;
2140 expected.data_channels_closed = 1;
Henrik Boström8dfc90f2022-09-02 07:39:292141 ASSERT_TRUE(report->Get("P"));
2142 EXPECT_EQ(expected, report->Get("P")->cast_to<RTCPeerConnectionStats>());
hbosd565b732016-08-30 21:04:352143 }
hbos5bf9def2017-03-20 10:14:142144
2145 // Re-opening a data channel (or opening a new data channel that is re-using
2146 // the same address in memory) should increase the opened count.
2147 dummy_channel_b->SignalOpened(dummy_channel_b.get());
2148
2149 {
Steve Anton5b387312018-02-03 00:00:202150 rtc::scoped_refptr<const RTCStatsReport> report =
2151 stats_->GetFreshStatsReport();
Philipp Hanckeb81823a2023-01-04 14:17:422152 RTCPeerConnectionStats expected("P", report->timestamp());
hbos5bf9def2017-03-20 10:14:142153 expected.data_channels_opened = 3;
2154 expected.data_channels_closed = 1;
Henrik Boström8dfc90f2022-09-02 07:39:292155 ASSERT_TRUE(report->Get("P"));
2156 EXPECT_EQ(expected, report->Get("P")->cast_to<RTCPeerConnectionStats>());
hbos5bf9def2017-03-20 10:14:142157 }
2158
2159 dummy_channel_a->SignalClosed(dummy_channel_a.get());
2160 dummy_channel_b->SignalClosed(dummy_channel_b.get());
2161
2162 {
Steve Anton5b387312018-02-03 00:00:202163 rtc::scoped_refptr<const RTCStatsReport> report =
2164 stats_->GetFreshStatsReport();
Philipp Hanckeb81823a2023-01-04 14:17:422165 RTCPeerConnectionStats expected("P", report->timestamp());
hbos5bf9def2017-03-20 10:14:142166 expected.data_channels_opened = 3;
2167 expected.data_channels_closed = 3;
Henrik Boström8dfc90f2022-09-02 07:39:292168 ASSERT_TRUE(report->Get("P"));
2169 EXPECT_EQ(expected, report->Get("P")->cast_to<RTCPeerConnectionStats>());
hbos5bf9def2017-03-20 10:14:142170 }
hbosd565b732016-08-30 21:04:352171}
2172
hbos09bc1282016-11-08 14:29:222173TEST_F(RTCStatsCollectorTest,
Harald Alvestranda3dab842018-01-14 08:18:582174 CollectLocalRTCMediaStreamStatsAndRTCMediaStreamTrackStats_Audio) {
hbos09bc1282016-11-08 14:29:222175 rtc::scoped_refptr<MediaStream> local_stream =
Seth Hampson845e8782018-03-02 19:34:102176 MediaStream::Create("LocalStreamId");
Steve Anton5b387312018-02-03 00:00:202177 pc_->mutable_local_streams()->AddStream(local_stream);
hbos09bc1282016-11-08 14:29:222178
2179 // Local audio track
hbos9e302742017-01-20 10:47:102180 rtc::scoped_refptr<MediaStreamTrackInterface> local_audio_track =
2181 CreateFakeTrack(cricket::MEDIA_TYPE_AUDIO, "LocalAudioTrackID",
2182 MediaStreamTrackInterface::kEnded);
Harald Alvestrand2f7ad282022-04-21 11:35:432183 local_stream->AddTrack(rtc::scoped_refptr<AudioTrackInterface>(
2184 static_cast<AudioTrackInterface*>(local_audio_track.get())));
hbos9e302742017-01-20 10:47:102185
2186 cricket::VoiceSenderInfo voice_sender_info_ssrc1;
2187 voice_sender_info_ssrc1.local_stats.push_back(cricket::SsrcSenderInfo());
2188 voice_sender_info_ssrc1.local_stats[0].ssrc = 1;
Ivo Creusen56d460902017-11-24 16:29:592189 voice_sender_info_ssrc1.apm_statistics.echo_return_loss = 42.0;
2190 voice_sender_info_ssrc1.apm_statistics.echo_return_loss_enhancement = 52.0;
hbos9e302742017-01-20 10:47:102191
Steve Anton5b387312018-02-03 00:00:202192 stats_->CreateMockRtpSendersReceiversAndChannels(
Harald Alvestranda3dab842018-01-14 08:18:582193 {std::make_pair(local_audio_track.get(), voice_sender_info_ssrc1)}, {},
Seth Hampson13b8bad2018-03-13 23:05:282194 {}, {}, {local_stream->id()}, {});
Harald Alvestranda3dab842018-01-14 08:18:582195
Steve Anton5b387312018-02-03 00:00:202196 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Harald Alvestranda3dab842018-01-14 08:18:582197
Henrik Boström15166b22022-10-19 09:06:582198 DEPRECATED_RTCMediaStreamStats expected_local_stream(
2199 IdForType<DEPRECATED_RTCMediaStreamStats>(report.get()),
Philipp Hanckeb81823a2023-01-04 14:17:422200 report->timestamp());
Seth Hampson13b8bad2018-03-13 23:05:282201 expected_local_stream.stream_identifier = local_stream->id();
Harald Alvestranda3dab842018-01-14 08:18:582202 expected_local_stream.track_ids = {
Henrik Boström15166b22022-10-19 09:06:582203 IdForType<DEPRECATED_RTCMediaStreamTrackStats>(report.get())};
Harald Alvestranda3dab842018-01-14 08:18:582204 ASSERT_TRUE(report->Get(expected_local_stream.id()))
2205 << "Did not find " << expected_local_stream.id() << " in "
2206 << report->ToJson();
Henrik Boström15166b22022-10-19 09:06:582207 EXPECT_EQ(expected_local_stream,
2208 report->Get(expected_local_stream.id())
2209 ->cast_to<DEPRECATED_RTCMediaStreamStats>());
Harald Alvestranda3dab842018-01-14 08:18:582210
Henrik Boström15166b22022-10-19 09:06:582211 DEPRECATED_RTCMediaStreamTrackStats expected_local_audio_track_ssrc1(
2212 IdForType<DEPRECATED_RTCMediaStreamTrackStats>(report.get()),
Philipp Hanckeb81823a2023-01-04 14:17:422213 report->timestamp(), RTCMediaStreamTrackKind::kAudio);
Harald Alvestranda3dab842018-01-14 08:18:582214 expected_local_audio_track_ssrc1.track_identifier = local_audio_track->id();
Henrik Boström646fda02019-05-22 13:49:422215 expected_local_audio_track_ssrc1.media_source_id =
Henrik Boström8dfc90f2022-09-02 07:39:292216 "SA11"; // Attachment ID = SSRC + 10
Harald Alvestranda3dab842018-01-14 08:18:582217 expected_local_audio_track_ssrc1.remote_source = false;
2218 expected_local_audio_track_ssrc1.ended = true;
2219 expected_local_audio_track_ssrc1.detached = false;
Harald Alvestranda3dab842018-01-14 08:18:582220 expected_local_audio_track_ssrc1.echo_return_loss = 42.0;
2221 expected_local_audio_track_ssrc1.echo_return_loss_enhancement = 52.0;
2222 ASSERT_TRUE(report->Get(expected_local_audio_track_ssrc1.id()))
2223 << "Did not find " << expected_local_audio_track_ssrc1.id() << " in "
2224 << report->ToJson();
2225 EXPECT_EQ(expected_local_audio_track_ssrc1,
2226 report->Get(expected_local_audio_track_ssrc1.id())
Henrik Boström15166b22022-10-19 09:06:582227 ->cast_to<DEPRECATED_RTCMediaStreamTrackStats>());
Harald Alvestranda3dab842018-01-14 08:18:582228}
2229
2230TEST_F(RTCStatsCollectorTest,
2231 CollectRemoteRTCMediaStreamStatsAndRTCMediaStreamTrackStats_Audio) {
Harald Alvestranda3dab842018-01-14 08:18:582232 rtc::scoped_refptr<MediaStream> remote_stream =
Seth Hampson845e8782018-03-02 19:34:102233 MediaStream::Create("RemoteStreamId");
Steve Anton5b387312018-02-03 00:00:202234 pc_->mutable_remote_streams()->AddStream(remote_stream);
Harald Alvestranda3dab842018-01-14 08:18:582235
hbos09bc1282016-11-08 14:29:222236 // Remote audio track
hbos9e302742017-01-20 10:47:102237 rtc::scoped_refptr<MediaStreamTrackInterface> remote_audio_track =
2238 CreateFakeTrack(cricket::MEDIA_TYPE_AUDIO, "RemoteAudioTrackID",
2239 MediaStreamTrackInterface::kLive);
Harald Alvestrand2f7ad282022-04-21 11:35:432240 remote_stream->AddTrack(rtc::scoped_refptr<AudioTrackInterface>(
2241 static_cast<AudioTrackInterface*>(remote_audio_track.get())));
hbos9e302742017-01-20 10:47:102242
2243 cricket::VoiceReceiverInfo voice_receiver_info;
2244 voice_receiver_info.local_stats.push_back(cricket::SsrcReceiverInfo());
2245 voice_receiver_info.local_stats[0].ssrc = 3;
Philipp Hanckeaa83cc72020-10-27 08:50:362246 voice_receiver_info.audio_level = 16383; // [0,32767]
zsteine76bd3a2017-07-14 19:17:492247 voice_receiver_info.total_output_energy = 0.125;
Steve Anton2dbc69f2017-08-25 00:15:132248 voice_receiver_info.total_samples_received = 4567;
zsteine76bd3a2017-07-14 19:17:492249 voice_receiver_info.total_output_duration = 0.25;
Steve Anton2dbc69f2017-08-25 00:15:132250 voice_receiver_info.concealed_samples = 123;
Gustaf Ullberg9a2e9062017-09-18 07:28:202251 voice_receiver_info.concealment_events = 12;
Ivo Creusen8d8ffdb2019-04-30 07:45:212252 voice_receiver_info.inserted_samples_for_deceleration = 987;
2253 voice_receiver_info.removed_samples_for_acceleration = 876;
2254 voice_receiver_info.silent_concealed_samples = 765;
Byoungchan Lee899b29e2021-06-29 13:09:182255 voice_receiver_info.jitter_buffer_delay_seconds = 3.456;
Chen Xing0acffb52019-01-15 14:46:292256 voice_receiver_info.jitter_buffer_emitted_count = 13;
hbos9e302742017-01-20 10:47:102257
Steve Anton5b387312018-02-03 00:00:202258 stats_->CreateMockRtpSendersReceiversAndChannels(
Harald Alvestranda3dab842018-01-14 08:18:582259 {}, {std::make_pair(remote_audio_track.get(), voice_receiver_info)}, {},
2260 {}, {}, {remote_stream});
hbos09bc1282016-11-08 14:29:222261
Steve Anton5b387312018-02-03 00:00:202262 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos09bc1282016-11-08 14:29:222263
Henrik Boström15166b22022-10-19 09:06:582264 DEPRECATED_RTCMediaStreamStats expected_remote_stream(
2265 IdForType<DEPRECATED_RTCMediaStreamStats>(report.get()),
Philipp Hanckeb81823a2023-01-04 14:17:422266 report->timestamp());
Seth Hampson13b8bad2018-03-13 23:05:282267 expected_remote_stream.stream_identifier = remote_stream->id();
Niels Möllerafb246b2022-04-20 12:26:502268 expected_remote_stream.track_ids = std::vector<std::string>(
Henrik Boström15166b22022-10-19 09:06:582269 {IdForType<DEPRECATED_RTCMediaStreamTrackStats>(report.get())});
Harald Alvestranda3dab842018-01-14 08:18:582270 ASSERT_TRUE(report->Get(expected_remote_stream.id()))
2271 << "Did not find " << expected_remote_stream.id() << " in "
2272 << report->ToJson();
Henrik Boström15166b22022-10-19 09:06:582273 EXPECT_EQ(expected_remote_stream,
2274 report->Get(expected_remote_stream.id())
2275 ->cast_to<DEPRECATED_RTCMediaStreamStats>());
hbos09bc1282016-11-08 14:29:222276
Henrik Boström15166b22022-10-19 09:06:582277 DEPRECATED_RTCMediaStreamTrackStats expected_remote_audio_track(
2278 IdForType<DEPRECATED_RTCMediaStreamTrackStats>(report.get()),
Philipp Hanckeb81823a2023-01-04 14:17:422279 report->timestamp(), RTCMediaStreamTrackKind::kAudio);
hbos09bc1282016-11-08 14:29:222280 expected_remote_audio_track.track_identifier = remote_audio_track->id();
Artem Titovcfea2182021-08-09 23:22:312281 // `expected_remote_audio_track.media_source_id` should be undefined
Henrik Boström646fda02019-05-22 13:49:422282 // because the track is remote.
hbos09bc1282016-11-08 14:29:222283 expected_remote_audio_track.remote_source = true;
2284 expected_remote_audio_track.ended = false;
2285 expected_remote_audio_track.detached = false;
Philipp Hanckeaa83cc72020-10-27 08:50:362286 expected_remote_audio_track.audio_level = 16383.0 / 32767.0; // [0,1]
zsteine76bd3a2017-07-14 19:17:492287 expected_remote_audio_track.total_audio_energy = 0.125;
Steve Anton2dbc69f2017-08-25 00:15:132288 expected_remote_audio_track.total_samples_received = 4567;
zsteine76bd3a2017-07-14 19:17:492289 expected_remote_audio_track.total_samples_duration = 0.25;
Steve Anton2dbc69f2017-08-25 00:15:132290 expected_remote_audio_track.concealed_samples = 123;
Gustaf Ullberg9a2e9062017-09-18 07:28:202291 expected_remote_audio_track.concealment_events = 12;
Ivo Creusen8d8ffdb2019-04-30 07:45:212292 expected_remote_audio_track.inserted_samples_for_deceleration = 987;
2293 expected_remote_audio_track.removed_samples_for_acceleration = 876;
2294 expected_remote_audio_track.silent_concealed_samples = 765;
Byoungchan Lee899b29e2021-06-29 13:09:182295 expected_remote_audio_track.jitter_buffer_delay = 3.456;
Chen Xing0acffb52019-01-15 14:46:292296 expected_remote_audio_track.jitter_buffer_emitted_count = 13;
hbosdbb64d82016-12-21 09:57:462297 ASSERT_TRUE(report->Get(expected_remote_audio_track.id()));
hbos09bc1282016-11-08 14:29:222298 EXPECT_EQ(expected_remote_audio_track,
Yves Gerey665174f2018-06-19 13:03:052299 report->Get(expected_remote_audio_track.id())
Henrik Boström15166b22022-10-19 09:06:582300 ->cast_to<DEPRECATED_RTCMediaStreamTrackStats>());
hbos09bc1282016-11-08 14:29:222301}
2302
2303TEST_F(RTCStatsCollectorTest,
Harald Alvestranda3dab842018-01-14 08:18:582304 CollectLocalRTCMediaStreamStatsAndRTCMediaStreamTrackStats_Video) {
hbos09bc1282016-11-08 14:29:222305 rtc::scoped_refptr<MediaStream> local_stream =
Seth Hampson845e8782018-03-02 19:34:102306 MediaStream::Create("LocalStreamId");
Steve Anton5b387312018-02-03 00:00:202307 pc_->mutable_local_streams()->AddStream(local_stream);
hbos09bc1282016-11-08 14:29:222308
2309 // Local video track
hbos9e302742017-01-20 10:47:102310 rtc::scoped_refptr<MediaStreamTrackInterface> local_video_track =
2311 CreateFakeTrack(cricket::MEDIA_TYPE_VIDEO, "LocalVideoTrackID",
2312 MediaStreamTrackInterface::kLive);
Harald Alvestrand2f7ad282022-04-21 11:35:432313 local_stream->AddTrack(rtc::scoped_refptr<VideoTrackInterface>(
2314 static_cast<VideoTrackInterface*>(local_video_track.get())));
hbos09bc1282016-11-08 14:29:222315
hbos9e302742017-01-20 10:47:102316 cricket::VideoSenderInfo video_sender_info_ssrc1;
2317 video_sender_info_ssrc1.local_stats.push_back(cricket::SsrcSenderInfo());
2318 video_sender_info_ssrc1.local_stats[0].ssrc = 1;
2319 video_sender_info_ssrc1.send_frame_width = 1234;
2320 video_sender_info_ssrc1.send_frame_height = 4321;
hbosfefe0762017-01-20 14:14:252321 video_sender_info_ssrc1.frames_encoded = 11;
Ilya Nikolaevskiy70473fc2018-02-28 15:35:032322 video_sender_info_ssrc1.huge_frames_sent = 1;
hbos9e302742017-01-20 10:47:102323
Steve Anton5b387312018-02-03 00:00:202324 stats_->CreateMockRtpSendersReceiversAndChannels(
Harald Alvestranda3dab842018-01-14 08:18:582325 {}, {},
2326 {std::make_pair(local_video_track.get(), video_sender_info_ssrc1)}, {},
Seth Hampson13b8bad2018-03-13 23:05:282327 {local_stream->id()}, {});
Harald Alvestranda3dab842018-01-14 08:18:582328
Steve Anton5b387312018-02-03 00:00:202329 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Harald Alvestranda3dab842018-01-14 08:18:582330
Henrik Boström15166b22022-10-19 09:06:582331 auto stats_of_my_type =
2332 report->GetStatsOfType<DEPRECATED_RTCMediaStreamStats>();
Mirko Bonadeie12c1fe2018-07-03 10:53:232333 ASSERT_EQ(1U, stats_of_my_type.size()) << "No stream in " << report->ToJson();
Henrik Boström15166b22022-10-19 09:06:582334 auto stats_of_track_type =
2335 report->GetStatsOfType<DEPRECATED_RTCMediaStreamTrackStats>();
Mirko Bonadeie12c1fe2018-07-03 10:53:232336 ASSERT_EQ(1U, stats_of_track_type.size())
Harald Alvestranda3dab842018-01-14 08:18:582337 << "Wrong number of tracks in " << report->ToJson();
2338
Henrik Boström15166b22022-10-19 09:06:582339 DEPRECATED_RTCMediaStreamStats expected_local_stream(
Philipp Hanckeb81823a2023-01-04 14:17:422340 stats_of_my_type[0]->id(), report->timestamp());
Seth Hampson13b8bad2018-03-13 23:05:282341 expected_local_stream.stream_identifier = local_stream->id();
Harald Alvestranda3dab842018-01-14 08:18:582342 expected_local_stream.track_ids =
2343 std::vector<std::string>({stats_of_track_type[0]->id()});
2344 ASSERT_TRUE(report->Get(expected_local_stream.id()));
Henrik Boström15166b22022-10-19 09:06:582345 EXPECT_EQ(expected_local_stream,
2346 report->Get(expected_local_stream.id())
2347 ->cast_to<DEPRECATED_RTCMediaStreamStats>());
Harald Alvestranda3dab842018-01-14 08:18:582348
Henrik Boström15166b22022-10-19 09:06:582349 DEPRECATED_RTCMediaStreamTrackStats expected_local_video_track_ssrc1(
Philipp Hanckeb81823a2023-01-04 14:17:422350 stats_of_track_type[0]->id(), report->timestamp(),
Harald Alvestranda3dab842018-01-14 08:18:582351 RTCMediaStreamTrackKind::kVideo);
2352 expected_local_video_track_ssrc1.track_identifier = local_video_track->id();
Henrik Boström646fda02019-05-22 13:49:422353 expected_local_video_track_ssrc1.media_source_id =
Henrik Boström8dfc90f2022-09-02 07:39:292354 "SV11"; // Attachment ID = SSRC + 10
Harald Alvestranda3dab842018-01-14 08:18:582355 expected_local_video_track_ssrc1.remote_source = false;
2356 expected_local_video_track_ssrc1.ended = false;
2357 expected_local_video_track_ssrc1.detached = false;
2358 expected_local_video_track_ssrc1.frame_width = 1234;
2359 expected_local_video_track_ssrc1.frame_height = 4321;
2360 expected_local_video_track_ssrc1.frames_sent = 11;
Ilya Nikolaevskiy70473fc2018-02-28 15:35:032361 expected_local_video_track_ssrc1.huge_frames_sent = 1;
Harald Alvestranda3dab842018-01-14 08:18:582362 ASSERT_TRUE(report->Get(expected_local_video_track_ssrc1.id()));
2363 EXPECT_EQ(expected_local_video_track_ssrc1,
2364 report->Get(expected_local_video_track_ssrc1.id())
Henrik Boström15166b22022-10-19 09:06:582365 ->cast_to<DEPRECATED_RTCMediaStreamTrackStats>());
Harald Alvestranda3dab842018-01-14 08:18:582366}
2367
2368TEST_F(RTCStatsCollectorTest,
2369 CollectRemoteRTCMediaStreamStatsAndRTCMediaStreamTrackStats_Video) {
Harald Alvestranda3dab842018-01-14 08:18:582370 rtc::scoped_refptr<MediaStream> remote_stream =
Seth Hampson845e8782018-03-02 19:34:102371 MediaStream::Create("RemoteStreamId");
Steve Anton5b387312018-02-03 00:00:202372 pc_->mutable_remote_streams()->AddStream(remote_stream);
Harald Alvestranda3dab842018-01-14 08:18:582373
hbos9e302742017-01-20 10:47:102374 // Remote video track with values
2375 rtc::scoped_refptr<MediaStreamTrackInterface> remote_video_track_ssrc3 =
2376 CreateFakeTrack(cricket::MEDIA_TYPE_VIDEO, "RemoteVideoTrackID3",
2377 MediaStreamTrackInterface::kEnded);
Harald Alvestrand2f7ad282022-04-21 11:35:432378 remote_stream->AddTrack(rtc::scoped_refptr<VideoTrackInterface>(
2379 static_cast<VideoTrackInterface*>(remote_video_track_ssrc3.get())));
hbos9e302742017-01-20 10:47:102380
2381 cricket::VideoReceiverInfo video_receiver_info_ssrc3;
2382 video_receiver_info_ssrc3.local_stats.push_back(cricket::SsrcReceiverInfo());
2383 video_receiver_info_ssrc3.local_stats[0].ssrc = 3;
2384 video_receiver_info_ssrc3.frame_width = 6789;
2385 video_receiver_info_ssrc3.frame_height = 9876;
Guido Urdaneta67378412019-05-28 15:38:082386 video_receiver_info_ssrc3.jitter_buffer_delay_seconds = 2.5;
2387 video_receiver_info_ssrc3.jitter_buffer_emitted_count = 25;
hbos50cfe1f2017-01-23 15:21:552388 video_receiver_info_ssrc3.frames_received = 1000;
2389 video_receiver_info_ssrc3.frames_decoded = 995;
Johannes Kron0c141c52019-08-26 13:04:432390 video_receiver_info_ssrc3.frames_dropped = 10;
hbos50cfe1f2017-01-23 15:21:552391 video_receiver_info_ssrc3.frames_rendered = 990;
hbos9e302742017-01-20 10:47:102392
Steve Anton5b387312018-02-03 00:00:202393 stats_->CreateMockRtpSendersReceiversAndChannels(
Harald Alvestranda3dab842018-01-14 08:18:582394 {}, {}, {},
Harald Alvestrandc72af932018-01-11 16:18:192395 {std::make_pair(remote_video_track_ssrc3.get(),
Harald Alvestranda3dab842018-01-14 08:18:582396 video_receiver_info_ssrc3)},
2397 {}, {remote_stream});
hbos09bc1282016-11-08 14:29:222398
Steve Anton5b387312018-02-03 00:00:202399 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos09bc1282016-11-08 14:29:222400
Henrik Boström15166b22022-10-19 09:06:582401 auto stats_of_my_type =
2402 report->GetStatsOfType<DEPRECATED_RTCMediaStreamStats>();
Mirko Bonadeie12c1fe2018-07-03 10:53:232403 ASSERT_EQ(1U, stats_of_my_type.size()) << "No stream in " << report->ToJson();
Henrik Boström15166b22022-10-19 09:06:582404 auto stats_of_track_type =
2405 report->GetStatsOfType<DEPRECATED_RTCMediaStreamTrackStats>();
Mirko Bonadeie12c1fe2018-07-03 10:53:232406 ASSERT_EQ(1U, stats_of_track_type.size())
Harald Alvestranda3dab842018-01-14 08:18:582407 << "Wrong number of tracks in " << report->ToJson();
2408 ASSERT_TRUE(*(stats_of_track_type[0]->remote_source));
hbos09bc1282016-11-08 14:29:222409
Henrik Boström15166b22022-10-19 09:06:582410 DEPRECATED_RTCMediaStreamStats expected_remote_stream(
Philipp Hanckeb81823a2023-01-04 14:17:422411 stats_of_my_type[0]->id(), report->timestamp());
Seth Hampson13b8bad2018-03-13 23:05:282412 expected_remote_stream.stream_identifier = remote_stream->id();
Harald Alvestranda3dab842018-01-14 08:18:582413 expected_remote_stream.track_ids =
2414 std::vector<std::string>({stats_of_track_type[0]->id()});
hbosdbb64d82016-12-21 09:57:462415 ASSERT_TRUE(report->Get(expected_remote_stream.id()));
Henrik Boström15166b22022-10-19 09:06:582416 EXPECT_EQ(expected_remote_stream,
2417 report->Get(expected_remote_stream.id())
2418 ->cast_to<DEPRECATED_RTCMediaStreamStats>());
hbos09bc1282016-11-08 14:29:222419
Henrik Boström15166b22022-10-19 09:06:582420 DEPRECATED_RTCMediaStreamTrackStats expected_remote_video_track_ssrc3(
Philipp Hanckeb81823a2023-01-04 14:17:422421 stats_of_track_type[0]->id(), report->timestamp(),
Harald Alvestranda3dab842018-01-14 08:18:582422 RTCMediaStreamTrackKind::kVideo);
hbos9e302742017-01-20 10:47:102423 expected_remote_video_track_ssrc3.track_identifier =
2424 remote_video_track_ssrc3->id();
Artem Titovcfea2182021-08-09 23:22:312425 // `expected_remote_video_track_ssrc3.media_source_id` should be undefined
Henrik Boström646fda02019-05-22 13:49:422426 // because the track is remote.
hbos9e302742017-01-20 10:47:102427 expected_remote_video_track_ssrc3.remote_source = true;
2428 expected_remote_video_track_ssrc3.ended = true;
2429 expected_remote_video_track_ssrc3.detached = false;
2430 expected_remote_video_track_ssrc3.frame_width = 6789;
2431 expected_remote_video_track_ssrc3.frame_height = 9876;
Guido Urdaneta67378412019-05-28 15:38:082432 expected_remote_video_track_ssrc3.jitter_buffer_delay = 2.5;
2433 expected_remote_video_track_ssrc3.jitter_buffer_emitted_count = 25;
hbos50cfe1f2017-01-23 15:21:552434 expected_remote_video_track_ssrc3.frames_received = 1000;
2435 expected_remote_video_track_ssrc3.frames_decoded = 995;
Johannes Kron0c141c52019-08-26 13:04:432436 expected_remote_video_track_ssrc3.frames_dropped = 10;
Sergey Silkin02371062019-01-31 15:45:422437
hbos9e302742017-01-20 10:47:102438 ASSERT_TRUE(report->Get(expected_remote_video_track_ssrc3.id()));
2439 EXPECT_EQ(expected_remote_video_track_ssrc3,
Yves Gerey665174f2018-06-19 13:03:052440 report->Get(expected_remote_video_track_ssrc3.id())
Henrik Boström15166b22022-10-19 09:06:582441 ->cast_to<DEPRECATED_RTCMediaStreamTrackStats>());
hbos09bc1282016-11-08 14:29:222442}
2443
hboseeafe942016-11-01 10:00:172444TEST_F(RTCStatsCollectorTest, CollectRTCInboundRTPStreamStats_Audio) {
hboseeafe942016-11-01 10:00:172445 cricket::VoiceMediaInfo voice_media_info;
hbos0adb8282016-11-23 10:32:062446
hboseeafe942016-11-01 10:00:172447 voice_media_info.receivers.push_back(cricket::VoiceReceiverInfo());
2448 voice_media_info.receivers[0].local_stats.push_back(
2449 cricket::SsrcReceiverInfo());
2450 voice_media_info.receivers[0].local_stats[0].ssrc = 1;
Harald Alvestrand719487e2017-12-13 11:26:042451 voice_media_info.receivers[0].packets_lost = -1; // Signed per RFC3550
Minyue Li28a2c632021-07-07 13:53:382452 voice_media_info.receivers[0].packets_discarded = 7788;
hboseeafe942016-11-01 10:00:172453 voice_media_info.receivers[0].packets_rcvd = 2;
Jakob Ivarssone54914a2021-07-01 09:16:052454 voice_media_info.receivers[0].nacks_sent = 5;
Ivo Creusen8d8ffdb2019-04-30 07:45:212455 voice_media_info.receivers[0].fec_packets_discarded = 5566;
2456 voice_media_info.receivers[0].fec_packets_received = 6677;
Niels Möllerac0a4cb2019-10-09 13:01:332457 voice_media_info.receivers[0].payload_bytes_rcvd = 3;
2458 voice_media_info.receivers[0].header_and_padding_bytes_rcvd = 4;
Oskar Sundbomcbc71b22017-11-16 09:56:072459 voice_media_info.receivers[0].codec_payload_type = 42;
hboseeafe942016-11-01 10:00:172460 voice_media_info.receivers[0].jitter_ms = 4500;
Eldar Rello4e5bc9f2020-07-06 11:18:072461 voice_media_info.receivers[0].jitter_buffer_delay_seconds = 1.0;
Ivo Creusen11fdb082022-07-04 12:16:392462 voice_media_info.receivers[0].jitter_buffer_target_delay_seconds = 1.1;
Ivo Creusen1a84b562022-07-19 14:33:102463 voice_media_info.receivers[0].jitter_buffer_minimum_delay_seconds = 0.999;
Eldar Rello4e5bc9f2020-07-06 11:18:072464 voice_media_info.receivers[0].jitter_buffer_emitted_count = 2;
2465 voice_media_info.receivers[0].total_samples_received = 3;
2466 voice_media_info.receivers[0].concealed_samples = 4;
2467 voice_media_info.receivers[0].silent_concealed_samples = 5;
2468 voice_media_info.receivers[0].concealment_events = 6;
2469 voice_media_info.receivers[0].inserted_samples_for_deceleration = 7;
2470 voice_media_info.receivers[0].removed_samples_for_acceleration = 8;
Philipp Hanckeaa83cc72020-10-27 08:50:362471 voice_media_info.receivers[0].audio_level = 14442; // [0,32767]
Eldar Rello4e5bc9f2020-07-06 11:18:072472 voice_media_info.receivers[0].total_output_energy = 10.0;
2473 voice_media_info.receivers[0].total_output_duration = 11.0;
Henrik Boström2fb83072022-10-06 11:37:112474 voice_media_info.receivers[0].jitter_buffer_flushes = 7;
2475 voice_media_info.receivers[0].delayed_packet_outage_samples = 15;
2476 voice_media_info.receivers[0].relative_packet_arrival_delay_seconds = 16;
2477 voice_media_info.receivers[0].interruption_count = 7788;
2478 voice_media_info.receivers[0].total_interruption_duration_ms = 778899;
Eldar Rello4e5bc9f2020-07-06 11:18:072479
Henrik Boström01738c62019-04-15 15:32:002480 voice_media_info.receivers[0].last_packet_received_timestamp_ms =
2481 absl::nullopt;
hbos0adb8282016-11-23 10:32:062482
2483 RtpCodecParameters codec_parameters;
2484 codec_parameters.payload_type = 42;
deadbeefe702b302017-02-04 20:09:012485 codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
2486 codec_parameters.name = "dummy";
Oskar Sundbomcbc71b22017-11-16 09:56:072487 codec_parameters.clock_rate = 0;
hbos0adb8282016-11-23 10:32:062488 voice_media_info.receive_codecs.insert(
2489 std::make_pair(codec_parameters.payload_type, codec_parameters));
2490
Tommi19015512022-02-02 10:49:352491 auto* voice_media_channel =
2492 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Henrik Boström5b3541f2018-03-19 12:52:562493 stats_->SetupRemoteTrackAndReceiver(
2494 cricket::MEDIA_TYPE_AUDIO, "RemoteAudioTrackID", "RemoteStreamId", 1);
hboseeafe942016-11-01 10:00:172495
Steve Anton5b387312018-02-03 00:00:202496 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hboseeafe942016-11-01 10:00:172497
Henrik Boström15166b22022-10-19 09:06:582498 auto stats_of_track_type =
2499 report->GetStatsOfType<DEPRECATED_RTCMediaStreamTrackStats>();
Mirko Bonadeie12c1fe2018-07-03 10:53:232500 ASSERT_EQ(1U, stats_of_track_type.size());
Harald Alvestranda3dab842018-01-14 08:18:582501
Henrik Boströmb43e3bb2022-09-26 10:36:442502 RTCInboundRTPStreamStats expected_audio("ITTransportName1A1",
Philipp Hanckeb81823a2023-01-04 14:17:422503 report->timestamp());
hbos3443bb72017-02-07 14:28:112504 expected_audio.ssrc = 1;
hboseeafe942016-11-01 10:00:172505 expected_audio.media_type = "audio";
Philipp Hancke3bc01662018-08-28 12:55:032506 expected_audio.kind = "audio";
Henrik Boströma6c7d5c2022-06-16 14:55:312507 expected_audio.track_identifier = "RemoteAudioTrackID";
Henrik Boström1ab61882022-06-16 15:07:332508 expected_audio.mid = "AudioMid";
Harald Alvestranda3dab842018-01-14 08:18:582509 expected_audio.track_id = stats_of_track_type[0]->id();
Henrik Boström8dfc90f2022-09-02 07:39:292510 expected_audio.transport_id = "TTransportName1";
2511 expected_audio.codec_id = "CITTransportName1_42";
hboseeafe942016-11-01 10:00:172512 expected_audio.packets_received = 2;
Jakob Ivarssone54914a2021-07-01 09:16:052513 expected_audio.nack_count = 5;
Ivo Creusen8d8ffdb2019-04-30 07:45:212514 expected_audio.fec_packets_discarded = 5566;
2515 expected_audio.fec_packets_received = 6677;
hboseeafe942016-11-01 10:00:172516 expected_audio.bytes_received = 3;
Niels Möllerac0a4cb2019-10-09 13:01:332517 expected_audio.header_bytes_received = 4;
Harald Alvestrand719487e2017-12-13 11:26:042518 expected_audio.packets_lost = -1;
Minyue Li28a2c632021-07-07 13:53:382519 expected_audio.packets_discarded = 7788;
Artem Titovcfea2182021-08-09 23:22:312520 // `expected_audio.last_packet_received_timestamp` should be undefined.
hboseeafe942016-11-01 10:00:172521 expected_audio.jitter = 4.5;
Eldar Rello4e5bc9f2020-07-06 11:18:072522 expected_audio.jitter_buffer_delay = 1.0;
Ivo Creusen11fdb082022-07-04 12:16:392523 expected_audio.jitter_buffer_target_delay = 1.1;
Ivo Creusen1a84b562022-07-19 14:33:102524 expected_audio.jitter_buffer_minimum_delay = 0.999;
Eldar Rello4e5bc9f2020-07-06 11:18:072525 expected_audio.jitter_buffer_emitted_count = 2;
2526 expected_audio.total_samples_received = 3;
2527 expected_audio.concealed_samples = 4;
2528 expected_audio.silent_concealed_samples = 5;
2529 expected_audio.concealment_events = 6;
2530 expected_audio.inserted_samples_for_deceleration = 7;
2531 expected_audio.removed_samples_for_acceleration = 8;
Philipp Hanckeaa83cc72020-10-27 08:50:362532 expected_audio.audio_level = 14442.0 / 32767.0; // [0,1]
Eldar Rello4e5bc9f2020-07-06 11:18:072533 expected_audio.total_audio_energy = 10.0;
2534 expected_audio.total_samples_duration = 11.0;
Henrik Boström2fb83072022-10-06 11:37:112535 expected_audio.jitter_buffer_flushes = 7;
2536 expected_audio.delayed_packet_outage_samples = 15;
2537 expected_audio.relative_packet_arrival_delay = 16;
2538 expected_audio.interruption_count = 7788;
2539 expected_audio.total_interruption_duration = 778.899;
Eldar Rello4e5bc9f2020-07-06 11:18:072540
nissec8ee8822017-01-18 15:20:552541 ASSERT_TRUE(report->Get(expected_audio.id()));
hbosa51d4f32017-02-16 13:34:482542 EXPECT_EQ(
2543 report->Get(expected_audio.id())->cast_to<RTCInboundRTPStreamStats>(),
2544 expected_audio);
Henrik Boström01738c62019-04-15 15:32:002545
2546 // Set previously undefined values and "GetStats" again.
2547 voice_media_info.receivers[0].last_packet_received_timestamp_ms = 3000;
Alessio Bazzicac366d512021-03-22 14:36:532548 expected_audio.last_packet_received_timestamp = 3000.0;
Åsa Perssonfcf79cc2019-10-22 13:23:442549 voice_media_info.receivers[0].estimated_playout_ntp_timestamp_ms = 4567;
2550 expected_audio.estimated_playout_timestamp = 4567;
Henrik Boström01738c62019-04-15 15:32:002551 voice_media_channel->SetStats(voice_media_info);
2552
2553 report = stats_->GetFreshStatsReport();
2554
2555 ASSERT_TRUE(report->Get(expected_audio.id()));
2556 EXPECT_EQ(
2557 report->Get(expected_audio.id())->cast_to<RTCInboundRTPStreamStats>(),
2558 expected_audio);
hbosb0ae9202017-01-27 14:35:162559 EXPECT_TRUE(report->Get(*expected_audio.track_id));
hbos84abeb12017-01-16 14:16:442560 EXPECT_TRUE(report->Get(*expected_audio.transport_id));
2561 EXPECT_TRUE(report->Get(*expected_audio.codec_id));
hboseeafe942016-11-01 10:00:172562}
2563
2564TEST_F(RTCStatsCollectorTest, CollectRTCInboundRTPStreamStats_Video) {
hboseeafe942016-11-01 10:00:172565 cricket::VideoMediaInfo video_media_info;
hbos0adb8282016-11-23 10:32:062566
hboseeafe942016-11-01 10:00:172567 video_media_info.receivers.push_back(cricket::VideoReceiverInfo());
2568 video_media_info.receivers[0].local_stats.push_back(
2569 cricket::SsrcReceiverInfo());
2570 video_media_info.receivers[0].local_stats[0].ssrc = 1;
2571 video_media_info.receivers[0].packets_rcvd = 2;
hbos02cd4d62016-12-09 12:19:442572 video_media_info.receivers[0].packets_lost = 42;
Niels Möllerac0a4cb2019-10-09 13:01:332573 video_media_info.receivers[0].payload_bytes_rcvd = 3;
2574 video_media_info.receivers[0].header_and_padding_bytes_rcvd = 12;
Oskar Sundbomcbc71b22017-11-16 09:56:072575 video_media_info.receivers[0].codec_payload_type = 42;
hbos820f5782016-11-22 11:16:502576 video_media_info.receivers[0].firs_sent = 5;
2577 video_media_info.receivers[0].plis_sent = 6;
2578 video_media_info.receivers[0].nacks_sent = 7;
Eldar Rello4e5bc9f2020-07-06 11:18:072579 video_media_info.receivers[0].frames_received = 8;
2580 video_media_info.receivers[0].frames_decoded = 9;
Rasmus Brandt2efae772019-06-27 12:29:342581 video_media_info.receivers[0].key_frames_decoded = 3;
Eldar Rello4e5bc9f2020-07-06 11:18:072582 video_media_info.receivers[0].frames_dropped = 13;
Danil Chapovalov66cadcc2018-06-19 14:47:432583 video_media_info.receivers[0].qp_sum = absl::nullopt;
Philipp Hancked970b092022-06-17 05:34:232584 video_media_info.receivers[0].total_decode_time =
2585 webrtc::TimeDelta::Seconds(9);
Philipp Hanckea16a6a62022-04-25 10:21:302586 video_media_info.receivers[0].total_processing_delay =
2587 webrtc::TimeDelta::Millis(600);
Philipp Hancke0359ba22022-05-05 13:55:362588 video_media_info.receivers[0].total_assembly_time =
2589 webrtc::TimeDelta::Millis(500);
2590 video_media_info.receivers[0].frames_assembled_from_multiple_packets = 23;
Johannes Kron00376e12019-11-25 09:25:422591 video_media_info.receivers[0].total_inter_frame_delay = 0.123;
2592 video_media_info.receivers[0].total_squared_inter_frame_delay = 0.00456;
Henrik Boströmc57a28c2022-10-06 09:59:052593 video_media_info.receivers[0].pause_count = 2;
2594 video_media_info.receivers[0].total_pauses_duration_ms = 10000;
2595 video_media_info.receivers[0].freeze_count = 3;
2596 video_media_info.receivers[0].total_freezes_duration_ms = 1000;
Di Wu (RP Room Eng)8af6b492021-02-20 01:34:222597 video_media_info.receivers[0].jitter_ms = 1199;
Byoungchan Lee899b29e2021-06-29 13:09:182598 video_media_info.receivers[0].jitter_buffer_delay_seconds = 3.456;
Ivo Creusen11fdb082022-07-04 12:16:392599 video_media_info.receivers[0].jitter_buffer_target_delay_seconds = 1.1;
Ivo Creusen1a84b562022-07-19 14:33:102600 video_media_info.receivers[0].jitter_buffer_minimum_delay_seconds = 0.999;
Byoungchan Lee899b29e2021-06-29 13:09:182601 video_media_info.receivers[0].jitter_buffer_emitted_count = 13;
Johannes Kron00376e12019-11-25 09:25:422602
Henrik Boström01738c62019-04-15 15:32:002603 video_media_info.receivers[0].last_packet_received_timestamp_ms =
2604 absl::nullopt;
Henrik Boström2e069262019-04-09 11:59:312605 video_media_info.receivers[0].content_type = VideoContentType::UNSPECIFIED;
Åsa Perssonfcf79cc2019-10-22 13:23:442606 video_media_info.receivers[0].estimated_playout_ntp_timestamp_ms =
2607 absl::nullopt;
Henrik Boström6b430862019-08-16 11:09:512608 video_media_info.receivers[0].decoder_implementation_name = "";
Philipp Hancke6fb8d1a2022-05-30 10:37:042609 video_media_info.receivers[0].min_playout_delay_ms = 50;
Evan Shrubsole13c0be42022-10-31 11:03:102610 video_media_info.receivers[0].power_efficient_decoder = false;
hbos0adb8282016-11-23 10:32:062611
Philipp Hancke3719a0c2022-07-04 16:24:462612 // Note: these two values intentionally differ,
2613 // only the decoded one should show up.
2614 video_media_info.receivers[0].framerate_rcvd = 15;
2615 video_media_info.receivers[0].framerate_decoded = 5;
2616
hbos0adb8282016-11-23 10:32:062617 RtpCodecParameters codec_parameters;
2618 codec_parameters.payload_type = 42;
Philipp Hancke3719a0c2022-07-04 16:24:462619 codec_parameters.kind = cricket::MEDIA_TYPE_VIDEO;
deadbeefe702b302017-02-04 20:09:012620 codec_parameters.name = "dummy";
Oskar Sundbomcbc71b22017-11-16 09:56:072621 codec_parameters.clock_rate = 0;
hbos0adb8282016-11-23 10:32:062622 video_media_info.receive_codecs.insert(
2623 std::make_pair(codec_parameters.payload_type, codec_parameters));
2624
Tommi19015512022-02-02 10:49:352625 auto* video_media_channel =
2626 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström5b3541f2018-03-19 12:52:562627 stats_->SetupRemoteTrackAndReceiver(
2628 cricket::MEDIA_TYPE_VIDEO, "RemoteVideoTrackID", "RemoteStreamId", 1);
hboseeafe942016-11-01 10:00:172629
Steve Anton5b387312018-02-03 00:00:202630 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hboseeafe942016-11-01 10:00:172631
Henrik Boströmb43e3bb2022-09-26 10:36:442632 RTCInboundRTPStreamStats expected_video("ITTransportName1V1",
Philipp Hanckeb81823a2023-01-04 14:17:422633 report->timestamp());
hbos3443bb72017-02-07 14:28:112634 expected_video.ssrc = 1;
hbos820f5782016-11-22 11:16:502635 expected_video.media_type = "video";
Philipp Hancke3bc01662018-08-28 12:55:032636 expected_video.kind = "video";
Henrik Boströma6c7d5c2022-06-16 14:55:312637 expected_video.track_identifier = "RemoteVideoTrackID";
Henrik Boström1ab61882022-06-16 15:07:332638 expected_video.mid = "VideoMid";
Henrik Boström15166b22022-10-19 09:06:582639 expected_video.track_id =
2640 IdForType<DEPRECATED_RTCMediaStreamTrackStats>(report.get());
Henrik Boström8dfc90f2022-09-02 07:39:292641 expected_video.transport_id = "TTransportName1";
2642 expected_video.codec_id = "CITTransportName1_42";
hbos820f5782016-11-22 11:16:502643 expected_video.fir_count = 5;
2644 expected_video.pli_count = 6;
2645 expected_video.nack_count = 7;
2646 expected_video.packets_received = 2;
2647 expected_video.bytes_received = 3;
Niels Möllerac0a4cb2019-10-09 13:01:332648 expected_video.header_bytes_received = 12;
hbos02cd4d62016-12-09 12:19:442649 expected_video.packets_lost = 42;
Eldar Rello4e5bc9f2020-07-06 11:18:072650 expected_video.frames_received = 8;
2651 expected_video.frames_decoded = 9;
Rasmus Brandt2efae772019-06-27 12:29:342652 expected_video.key_frames_decoded = 3;
Eldar Rello4e5bc9f2020-07-06 11:18:072653 expected_video.frames_dropped = 13;
Artem Titovcfea2182021-08-09 23:22:312654 // `expected_video.qp_sum` should be undefined.
Johannes Kronbfd343b2019-07-01 08:07:502655 expected_video.total_decode_time = 9.0;
Philipp Hanckea16a6a62022-04-25 10:21:302656 expected_video.total_processing_delay = 0.6;
Philipp Hancke0359ba22022-05-05 13:55:362657 expected_video.total_assembly_time = 0.5;
2658 expected_video.frames_assembled_from_multiple_packets = 23;
Johannes Kron00376e12019-11-25 09:25:422659 expected_video.total_inter_frame_delay = 0.123;
2660 expected_video.total_squared_inter_frame_delay = 0.00456;
Henrik Boströmc57a28c2022-10-06 09:59:052661 expected_video.pause_count = 2;
2662 expected_video.total_pauses_duration = 10;
2663 expected_video.freeze_count = 3;
2664 expected_video.total_freezes_duration = 1;
Di Wu (RP Room Eng)8af6b492021-02-20 01:34:222665 expected_video.jitter = 1.199;
Byoungchan Lee899b29e2021-06-29 13:09:182666 expected_video.jitter_buffer_delay = 3.456;
Ivo Creusen11fdb082022-07-04 12:16:392667 expected_video.jitter_buffer_target_delay = 1.1;
Ivo Creusen1a84b562022-07-19 14:33:102668 expected_video.jitter_buffer_minimum_delay = 0.999;
Byoungchan Lee899b29e2021-06-29 13:09:182669 expected_video.jitter_buffer_emitted_count = 13;
Artem Titovcfea2182021-08-09 23:22:312670 // `expected_video.last_packet_received_timestamp` should be undefined.
2671 // `expected_video.content_type` should be undefined.
2672 // `expected_video.decoder_implementation` should be undefined.
Philipp Hancke6fb8d1a2022-05-30 10:37:042673 expected_video.min_playout_delay = 0.05;
Philipp Hancke3719a0c2022-07-04 16:24:462674 expected_video.frames_per_second = 5;
Evan Shrubsole13c0be42022-10-31 11:03:102675 expected_video.power_efficient_decoder = false;
hboseeafe942016-11-01 10:00:172676
nissec8ee8822017-01-18 15:20:552677 ASSERT_TRUE(report->Get(expected_video.id()));
hbosa51d4f32017-02-16 13:34:482678 EXPECT_EQ(
2679 report->Get(expected_video.id())->cast_to<RTCInboundRTPStreamStats>(),
2680 expected_video);
hboseeafe942016-11-01 10:00:172681
hbosa51d4f32017-02-16 13:34:482682 // Set previously undefined values and "GetStats" again.
Oskar Sundbomcbc71b22017-11-16 09:56:072683 video_media_info.receivers[0].qp_sum = 9;
hbosa51d4f32017-02-16 13:34:482684 expected_video.qp_sum = 9;
Åsa Perssonfcf79cc2019-10-22 13:23:442685 video_media_info.receivers[0].last_packet_received_timestamp_ms = 1000;
Alessio Bazzica5cf8c2c2021-03-24 07:51:262686 expected_video.last_packet_received_timestamp = 1000.0;
Henrik Boström2e069262019-04-09 11:59:312687 video_media_info.receivers[0].content_type = VideoContentType::SCREENSHARE;
2688 expected_video.content_type = "screenshare";
Åsa Perssonfcf79cc2019-10-22 13:23:442689 video_media_info.receivers[0].estimated_playout_ntp_timestamp_ms = 1234;
2690 expected_video.estimated_playout_timestamp = 1234;
Henrik Boström6b430862019-08-16 11:09:512691 video_media_info.receivers[0].decoder_implementation_name = "libfoodecoder";
2692 expected_video.decoder_implementation = "libfoodecoder";
Evan Shrubsole13c0be42022-10-31 11:03:102693 video_media_info.receivers[0].power_efficient_decoder = true;
2694 expected_video.power_efficient_decoder = true;
Steve Anton5b387312018-02-03 00:00:202695 video_media_channel->SetStats(video_media_info);
hbosa51d4f32017-02-16 13:34:482696
Steve Anton5b387312018-02-03 00:00:202697 report = stats_->GetFreshStatsReport();
hbosa51d4f32017-02-16 13:34:482698
2699 ASSERT_TRUE(report->Get(expected_video.id()));
2700 EXPECT_EQ(
2701 report->Get(expected_video.id())->cast_to<RTCInboundRTPStreamStats>(),
2702 expected_video);
hbosb0ae9202017-01-27 14:35:162703 EXPECT_TRUE(report->Get(*expected_video.track_id));
hbos84abeb12017-01-16 14:16:442704 EXPECT_TRUE(report->Get(*expected_video.transport_id));
hbosa51d4f32017-02-16 13:34:482705 EXPECT_TRUE(report->Get(*expected_video.codec_id));
hboseeafe942016-11-01 10:00:172706}
2707
Henrik Boströmc5f8f802022-10-19 15:50:092708TEST_F(RTCStatsCollectorTest, CollectGoogTimingFrameInfo) {
2709 cricket::VideoMediaInfo video_media_info;
2710
2711 video_media_info.receivers.push_back(cricket::VideoReceiverInfo());
2712 video_media_info.receivers[0].local_stats.push_back(
2713 cricket::SsrcReceiverInfo());
2714 video_media_info.receivers[0].local_stats[0].ssrc = 1;
2715 TimingFrameInfo timing_frame_info;
2716 timing_frame_info.rtp_timestamp = 1;
2717 timing_frame_info.capture_time_ms = 2;
2718 timing_frame_info.encode_start_ms = 3;
2719 timing_frame_info.encode_finish_ms = 4;
2720 timing_frame_info.packetization_finish_ms = 5;
2721 timing_frame_info.pacer_exit_ms = 6;
2722 timing_frame_info.network_timestamp_ms = 7;
2723 timing_frame_info.network2_timestamp_ms = 8;
2724 timing_frame_info.receive_start_ms = 9;
2725 timing_frame_info.receive_finish_ms = 10;
2726 timing_frame_info.decode_start_ms = 11;
2727 timing_frame_info.decode_finish_ms = 12;
2728 timing_frame_info.render_time_ms = 13;
2729 timing_frame_info.flags = 14;
2730 video_media_info.receivers[0].timing_frame_info = timing_frame_info;
2731
2732 pc_->AddVideoChannel("Mid0", "Transport0", video_media_info);
2733 stats_->SetupRemoteTrackAndReceiver(
2734 cricket::MEDIA_TYPE_VIDEO, "RemoteVideoTrackID", "RemoteStreamId", 1);
2735
2736 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
2737 auto inbound_rtps = report->GetStatsOfType<RTCInboundRTPStreamStats>();
2738 ASSERT_EQ(inbound_rtps.size(), 1u);
2739 ASSERT_TRUE(inbound_rtps[0]->goog_timing_frame_info.is_defined());
2740 EXPECT_EQ(*inbound_rtps[0]->goog_timing_frame_info,
2741 "1,2,3,4,5,6,7,8,9,10,11,12,13,1,0");
2742}
2743
hbos6ded1902016-11-01 08:50:462744TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRTPStreamStats_Audio) {
hbos6ded1902016-11-01 08:50:462745 cricket::VoiceMediaInfo voice_media_info;
hbos0adb8282016-11-23 10:32:062746
hbos6ded1902016-11-01 08:50:462747 voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
2748 voice_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
2749 voice_media_info.senders[0].local_stats[0].ssrc = 1;
2750 voice_media_info.senders[0].packets_sent = 2;
Henrik Boströmaebba7b2022-10-26 14:53:032751 voice_media_info.senders[0].total_packet_send_delay = TimeDelta::Seconds(1);
Henrik Boströmcf96e0f2019-04-17 11:51:532752 voice_media_info.senders[0].retransmitted_packets_sent = 20;
Niels Möllerac0a4cb2019-10-09 13:01:332753 voice_media_info.senders[0].payload_bytes_sent = 3;
2754 voice_media_info.senders[0].header_and_padding_bytes_sent = 12;
Henrik Boströmcf96e0f2019-04-17 11:51:532755 voice_media_info.senders[0].retransmitted_bytes_sent = 30;
Jakob Ivarssone91c9922021-07-06 07:55:432756 voice_media_info.senders[0].nacks_rcvd = 31;
Jakob Ivarssonbf087452021-11-11 12:43:492757 voice_media_info.senders[0].target_bitrate = 32000;
Oskar Sundbomcbc71b22017-11-16 09:56:072758 voice_media_info.senders[0].codec_payload_type = 42;
Philipp Hancke684e2412022-07-28 10:41:002759 voice_media_info.senders[0].active = true;
hbos0adb8282016-11-23 10:32:062760
2761 RtpCodecParameters codec_parameters;
2762 codec_parameters.payload_type = 42;
deadbeefe702b302017-02-04 20:09:012763 codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
2764 codec_parameters.name = "dummy";
Oskar Sundbomcbc71b22017-11-16 09:56:072765 codec_parameters.clock_rate = 0;
hbos0adb8282016-11-23 10:32:062766 voice_media_info.send_codecs.insert(
2767 std::make_pair(codec_parameters.payload_type, codec_parameters));
2768
Tommi19015512022-02-02 10:49:352769 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Steve Anton5b387312018-02-03 00:00:202770 stats_->SetupLocalTrackAndSender(cricket::MEDIA_TYPE_AUDIO,
Henrik Boström646fda02019-05-22 13:49:422771 "LocalAudioTrackID", 1, true,
2772 /*attachment_id=*/50);
hbos6ded1902016-11-01 08:50:462773
Steve Anton5b387312018-02-03 00:00:202774 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos6ded1902016-11-01 08:50:462775
Henrik Boströmb43e3bb2022-09-26 10:36:442776 RTCOutboundRTPStreamStats expected_audio("OTTransportName1A1",
Philipp Hanckeb81823a2023-01-04 14:17:422777 report->timestamp());
Henrik Boström8dfc90f2022-09-02 07:39:292778 expected_audio.media_source_id = "SA50";
Artem Titovcfea2182021-08-09 23:22:312779 // `expected_audio.remote_id` should be undefined.
Henrik Boström1ab61882022-06-16 15:07:332780 expected_audio.mid = "AudioMid";
hbos3443bb72017-02-07 14:28:112781 expected_audio.ssrc = 1;
hbos6ded1902016-11-01 08:50:462782 expected_audio.media_type = "audio";
Philipp Hancke3bc01662018-08-28 12:55:032783 expected_audio.kind = "audio";
Henrik Boström15166b22022-10-19 09:06:582784 expected_audio.track_id =
2785 IdForType<DEPRECATED_RTCMediaStreamTrackStats>(report.get());
Henrik Boström8dfc90f2022-09-02 07:39:292786 expected_audio.transport_id = "TTransportName1";
2787 expected_audio.codec_id = "COTTransportName1_42";
hbos6ded1902016-11-01 08:50:462788 expected_audio.packets_sent = 2;
Henrik Boströmaebba7b2022-10-26 14:53:032789 expected_audio.total_packet_send_delay = 1;
Henrik Boströmcf96e0f2019-04-17 11:51:532790 expected_audio.retransmitted_packets_sent = 20;
hbos6ded1902016-11-01 08:50:462791 expected_audio.bytes_sent = 3;
Niels Möllerac0a4cb2019-10-09 13:01:332792 expected_audio.header_bytes_sent = 12;
Henrik Boströmcf96e0f2019-04-17 11:51:532793 expected_audio.retransmitted_bytes_sent = 30;
Jakob Ivarssone91c9922021-07-06 07:55:432794 expected_audio.nack_count = 31;
Jakob Ivarssonbf087452021-11-11 12:43:492795 expected_audio.target_bitrate = 32000;
Philipp Hancke684e2412022-07-28 10:41:002796 expected_audio.active = true;
hboscd195be2017-02-07 16:31:272797
hboscd195be2017-02-07 16:31:272798 ASSERT_TRUE(report->Get(expected_audio.id()));
hbosa51d4f32017-02-16 13:34:482799 EXPECT_EQ(
2800 report->Get(expected_audio.id())->cast_to<RTCOutboundRTPStreamStats>(),
2801 expected_audio);
skvladed02c6d2017-02-07 18:45:312802
hbosa51d4f32017-02-16 13:34:482803 ASSERT_TRUE(report->Get(expected_audio.id()));
2804 EXPECT_EQ(
2805 report->Get(expected_audio.id())->cast_to<RTCOutboundRTPStreamStats>(),
2806 expected_audio);
hbosb0ae9202017-01-27 14:35:162807 EXPECT_TRUE(report->Get(*expected_audio.track_id));
hbos84abeb12017-01-16 14:16:442808 EXPECT_TRUE(report->Get(*expected_audio.transport_id));
2809 EXPECT_TRUE(report->Get(*expected_audio.codec_id));
hbos6ded1902016-11-01 08:50:462810}
2811
2812TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRTPStreamStats_Video) {
hbos6ded1902016-11-01 08:50:462813 cricket::VideoMediaInfo video_media_info;
hbos0adb8282016-11-23 10:32:062814
hbos6ded1902016-11-01 08:50:462815 video_media_info.senders.push_back(cricket::VideoSenderInfo());
2816 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
2817 video_media_info.senders[0].local_stats[0].ssrc = 1;
2818 video_media_info.senders[0].firs_rcvd = 2;
2819 video_media_info.senders[0].plis_rcvd = 3;
2820 video_media_info.senders[0].nacks_rcvd = 4;
2821 video_media_info.senders[0].packets_sent = 5;
Henrik Boströmcf96e0f2019-04-17 11:51:532822 video_media_info.senders[0].retransmitted_packets_sent = 50;
Niels Möllerac0a4cb2019-10-09 13:01:332823 video_media_info.senders[0].payload_bytes_sent = 6;
2824 video_media_info.senders[0].header_and_padding_bytes_sent = 12;
Henrik Boströmcf96e0f2019-04-17 11:51:532825 video_media_info.senders[0].retransmitted_bytes_sent = 60;
Oskar Sundbomcbc71b22017-11-16 09:56:072826 video_media_info.senders[0].codec_payload_type = 42;
hbos6769c492017-01-02 16:35:132827 video_media_info.senders[0].frames_encoded = 8;
Rasmus Brandt2efae772019-06-27 12:29:342828 video_media_info.senders[0].key_frames_encoded = 3;
Henrik Boströmf71362f2019-04-08 14:14:232829 video_media_info.senders[0].total_encode_time_ms = 9000;
Henrik Boström23aff9b2019-05-20 13:15:382830 video_media_info.senders[0].total_encoded_bytes_target = 1234;
Henrik Boströmd8199212022-10-26 14:50:532831 video_media_info.senders[0].total_packet_send_delay =
2832 webrtc::TimeDelta::Seconds(10);
Henrik Boströmce33b6a2019-05-28 15:42:382833 video_media_info.senders[0].quality_limitation_reason =
2834 QualityLimitationReason::kBandwidth;
Byoungchan Lee7d235352021-05-28 12:32:042835 video_media_info.senders[0].quality_limitation_durations_ms
2836 [webrtc::QualityLimitationReason::kBandwidth] = 300;
Evan Shrubsolecc62b162019-09-09 09:26:452837 video_media_info.senders[0].quality_limitation_resolution_changes = 56u;
Danil Chapovalov66cadcc2018-06-19 14:47:432838 video_media_info.senders[0].qp_sum = absl::nullopt;
Henrik Boström2e069262019-04-09 11:59:312839 video_media_info.senders[0].content_type = VideoContentType::UNSPECIFIED;
Henrik Boström6b430862019-08-16 11:09:512840 video_media_info.senders[0].encoder_implementation_name = "";
Evan Shrubsole13c0be42022-10-31 11:03:102841 video_media_info.senders[0].power_efficient_encoder = false;
Henrik Boströma0ff50c2020-05-05 13:54:462842 video_media_info.senders[0].send_frame_width = 200;
2843 video_media_info.senders[0].send_frame_height = 100;
2844 video_media_info.senders[0].framerate_sent = 10;
2845 video_media_info.senders[0].frames_sent = 5;
2846 video_media_info.senders[0].huge_frames_sent = 2;
Philipp Hancke684e2412022-07-28 10:41:002847 video_media_info.senders[0].active = false;
Evan Shrubsole9b235cd2022-12-06 10:09:102848 video_media_info.senders[0].scalability_mode = ScalabilityMode::kL3T3_KEY;
Henrik Boströma0ff50c2020-05-05 13:54:462849 video_media_info.aggregated_senders.push_back(video_media_info.senders[0]);
hbos0adb8282016-11-23 10:32:062850 RtpCodecParameters codec_parameters;
2851 codec_parameters.payload_type = 42;
deadbeefe702b302017-02-04 20:09:012852 codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
2853 codec_parameters.name = "dummy";
Oskar Sundbomcbc71b22017-11-16 09:56:072854 codec_parameters.clock_rate = 0;
hbos0adb8282016-11-23 10:32:062855 video_media_info.send_codecs.insert(
2856 std::make_pair(codec_parameters.payload_type, codec_parameters));
2857
Tommi19015512022-02-02 10:49:352858 auto* video_media_channel =
2859 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Steve Anton5b387312018-02-03 00:00:202860 stats_->SetupLocalTrackAndSender(cricket::MEDIA_TYPE_VIDEO,
Henrik Boström646fda02019-05-22 13:49:422861 "LocalVideoTrackID", 1, true,
2862 /*attachment_id=*/50);
hbos6ded1902016-11-01 08:50:462863
Steve Anton5b387312018-02-03 00:00:202864 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos6ded1902016-11-01 08:50:462865
Harald Alvestranda3dab842018-01-14 08:18:582866 auto stats_of_my_type = report->GetStatsOfType<RTCOutboundRTPStreamStats>();
Mirko Bonadeie12c1fe2018-07-03 10:53:232867 ASSERT_EQ(1U, stats_of_my_type.size());
Henrik Boström15166b22022-10-19 09:06:582868 auto stats_of_track_type =
2869 report->GetStatsOfType<DEPRECATED_RTCMediaStreamTrackStats>();
Mirko Bonadeie12c1fe2018-07-03 10:53:232870 ASSERT_EQ(1U, stats_of_track_type.size());
Harald Alvestranda3dab842018-01-14 08:18:582871
2872 RTCOutboundRTPStreamStats expected_video(stats_of_my_type[0]->id(),
Philipp Hanckeb81823a2023-01-04 14:17:422873 report->timestamp());
Henrik Boström8dfc90f2022-09-02 07:39:292874 expected_video.media_source_id = "SV50";
Artem Titovcfea2182021-08-09 23:22:312875 // `expected_video.remote_id` should be undefined.
Henrik Boström1ab61882022-06-16 15:07:332876 expected_video.mid = "VideoMid";
hbos3443bb72017-02-07 14:28:112877 expected_video.ssrc = 1;
hbos6ded1902016-11-01 08:50:462878 expected_video.media_type = "video";
Philipp Hancke3bc01662018-08-28 12:55:032879 expected_video.kind = "video";
Harald Alvestranda3dab842018-01-14 08:18:582880 expected_video.track_id = stats_of_track_type[0]->id();
Henrik Boström8dfc90f2022-09-02 07:39:292881 expected_video.transport_id = "TTransportName1";
2882 expected_video.codec_id = "COTTransportName1_42";
hbos6ded1902016-11-01 08:50:462883 expected_video.fir_count = 2;
2884 expected_video.pli_count = 3;
2885 expected_video.nack_count = 4;
2886 expected_video.packets_sent = 5;
Henrik Boströmcf96e0f2019-04-17 11:51:532887 expected_video.retransmitted_packets_sent = 50;
hbos6ded1902016-11-01 08:50:462888 expected_video.bytes_sent = 6;
Niels Möllerac0a4cb2019-10-09 13:01:332889 expected_video.header_bytes_sent = 12;
Henrik Boströmcf96e0f2019-04-17 11:51:532890 expected_video.retransmitted_bytes_sent = 60;
skvladed02c6d2017-02-07 18:45:312891 expected_video.frames_encoded = 8;
Rasmus Brandt2efae772019-06-27 12:29:342892 expected_video.key_frames_encoded = 3;
Henrik Boströmf71362f2019-04-08 14:14:232893 expected_video.total_encode_time = 9.0;
Henrik Boström23aff9b2019-05-20 13:15:382894 expected_video.total_encoded_bytes_target = 1234;
Henrik Boström9fe18342019-05-16 16:38:202895 expected_video.total_packet_send_delay = 10.0;
Henrik Boströmce33b6a2019-05-28 15:42:382896 expected_video.quality_limitation_reason = "bandwidth";
Byoungchan Lee7d235352021-05-28 12:32:042897 expected_video.quality_limitation_durations = std::map<std::string, double>{
Philipp Hancke3fd9cbc2022-01-10 16:41:432898 std::pair<std::string, double>{"bandwidth", 0.3},
Byoungchan Lee7d235352021-05-28 12:32:042899 };
Evan Shrubsolecc62b162019-09-09 09:26:452900 expected_video.quality_limitation_resolution_changes = 56u;
Eldar Rello9276e2c2020-06-10 14:53:392901 expected_video.frame_width = 200u;
2902 expected_video.frame_height = 100u;
2903 expected_video.frames_per_second = 10.0;
2904 expected_video.frames_sent = 5;
2905 expected_video.huge_frames_sent = 2;
Philipp Hancke684e2412022-07-28 10:41:002906 expected_video.active = false;
Evan Shrubsole13c0be42022-10-31 11:03:102907 expected_video.power_efficient_encoder = false;
Evan Shrubsole9b235cd2022-12-06 10:09:102908 expected_video.scalability_mode = "L3T3_KEY";
Artem Titovcfea2182021-08-09 23:22:312909 // `expected_video.content_type` should be undefined.
2910 // `expected_video.qp_sum` should be undefined.
2911 // `expected_video.encoder_implementation` should be undefined.
hboscd195be2017-02-07 16:31:272912 ASSERT_TRUE(report->Get(expected_video.id()));
Harald Alvestranda3dab842018-01-14 08:18:582913
hbosa51d4f32017-02-16 13:34:482914 EXPECT_EQ(
2915 report->Get(expected_video.id())->cast_to<RTCOutboundRTPStreamStats>(),
2916 expected_video);
skvladed02c6d2017-02-07 18:45:312917
hbosa51d4f32017-02-16 13:34:482918 // Set previously undefined values and "GetStats" again.
Oskar Sundbomcbc71b22017-11-16 09:56:072919 video_media_info.senders[0].qp_sum = 9;
hbosa51d4f32017-02-16 13:34:482920 expected_video.qp_sum = 9;
Henrik Boström2e069262019-04-09 11:59:312921 video_media_info.senders[0].content_type = VideoContentType::SCREENSHARE;
2922 expected_video.content_type = "screenshare";
Henrik Boström6b430862019-08-16 11:09:512923 video_media_info.senders[0].encoder_implementation_name = "libfooencoder";
Henrik Boströma0ff50c2020-05-05 13:54:462924 video_media_info.aggregated_senders[0] = video_media_info.senders[0];
Henrik Boström6b430862019-08-16 11:09:512925 expected_video.encoder_implementation = "libfooencoder";
Evan Shrubsole13c0be42022-10-31 11:03:102926 video_media_info.senders[0].power_efficient_encoder = true;
2927 expected_video.power_efficient_encoder = true;
Steve Anton5b387312018-02-03 00:00:202928 video_media_channel->SetStats(video_media_info);
hbosa51d4f32017-02-16 13:34:482929
Steve Anton5b387312018-02-03 00:00:202930 report = stats_->GetFreshStatsReport();
hbosa51d4f32017-02-16 13:34:482931
2932 ASSERT_TRUE(report->Get(expected_video.id()));
2933 EXPECT_EQ(
2934 report->Get(expected_video.id())->cast_to<RTCOutboundRTPStreamStats>(),
2935 expected_video);
hbosb0ae9202017-01-27 14:35:162936 EXPECT_TRUE(report->Get(*expected_video.track_id));
hbos84abeb12017-01-16 14:16:442937 EXPECT_TRUE(report->Get(*expected_video.transport_id));
2938 EXPECT_TRUE(report->Get(*expected_video.codec_id));
hbos6ded1902016-11-01 08:50:462939}
2940
hbos2fa7c672016-10-24 11:00:052941TEST_F(RTCStatsCollectorTest, CollectRTCTransportStats) {
Steve Anton5b387312018-02-03 00:00:202942 const char kTransportName[] = "transport";
2943
2944 pc_->AddVoiceChannel("audio", kTransportName);
2945
Gary Liu37e489c2017-11-21 18:49:362946 std::unique_ptr<cricket::Candidate> rtp_local_candidate =
2947 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
2948 cricket::LOCAL_PORT_TYPE, 42);
hbos2fa7c672016-10-24 11:00:052949 std::unique_ptr<cricket::Candidate> rtp_remote_candidate =
2950 CreateFakeCandidate("42.42.42.42", 42, "protocol",
Gary Liu37e489c2017-11-21 18:49:362951 rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
2952 42);
hbos2fa7c672016-10-24 11:00:052953 std::unique_ptr<cricket::Candidate> rtcp_local_candidate =
Gary Liu37e489c2017-11-21 18:49:362954 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
hbos2fa7c672016-10-24 11:00:052955 cricket::LOCAL_PORT_TYPE, 42);
2956 std::unique_ptr<cricket::Candidate> rtcp_remote_candidate =
2957 CreateFakeCandidate("42.42.42.42", 42, "protocol",
Gary Liu37e489c2017-11-21 18:49:362958 rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
2959 42);
hbos2fa7c672016-10-24 11:00:052960
hbos2fa7c672016-10-24 11:00:052961 cricket::ConnectionInfo rtp_connection_info;
2962 rtp_connection_info.best_connection = false;
2963 rtp_connection_info.local_candidate = *rtp_local_candidate.get();
2964 rtp_connection_info.remote_candidate = *rtp_remote_candidate.get();
2965 rtp_connection_info.sent_total_bytes = 42;
2966 rtp_connection_info.recv_total_bytes = 1337;
Artem Titovedacbd52020-07-06 14:06:372967 rtp_connection_info.sent_total_packets = 3;
2968 rtp_connection_info.sent_discarded_packets = 2;
2969 rtp_connection_info.packets_received = 4;
hbos2fa7c672016-10-24 11:00:052970 cricket::TransportChannelStats rtp_transport_channel_stats;
2971 rtp_transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
Jonas Oreland149dc722019-08-28 06:10:272972 rtp_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
2973 rtp_connection_info);
Mirko Bonadei9f6808b2021-05-21 18:46:092974 rtp_transport_channel_stats.dtls_state = DtlsTransportState::kNew;
Jonas Oreland42da5a92022-03-01 12:55:372975 rtp_transport_channel_stats.ice_transport_stats.bytes_sent = 42;
2976 rtp_transport_channel_stats.ice_transport_stats.packets_sent = 1;
2977 rtp_transport_channel_stats.ice_transport_stats.bytes_received = 1337;
2978 rtp_transport_channel_stats.ice_transport_stats.packets_received = 4;
Jonas Oreland149dc722019-08-28 06:10:272979 rtp_transport_channel_stats.ice_transport_stats
2980 .selected_candidate_pair_changes = 1;
Philipp Hancke95b1a342022-05-05 05:53:542981 rtp_transport_channel_stats.ice_transport_stats.ice_local_username_fragment =
2982 "thelocalufrag";
Steve Anton5b387312018-02-03 00:00:202983 pc_->SetTransportStats(kTransportName, {rtp_transport_channel_stats});
hbos2fa7c672016-10-24 11:00:052984
2985 // Get stats without RTCP, an active connection or certificates.
Steve Anton5b387312018-02-03 00:00:202986 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos0583b282016-11-30 09:50:142987
2988 RTCTransportStats expected_rtp_transport(
Henrik Boström8dfc90f2022-09-02 07:39:292989 "Ttransport" + rtc::ToString(cricket::ICE_CANDIDATE_COMPONENT_RTP),
Philipp Hanckeb81823a2023-01-04 14:17:422990 report->timestamp());
hbos0583b282016-11-30 09:50:142991 expected_rtp_transport.bytes_sent = 42;
Artem Titovedacbd52020-07-06 14:06:372992 expected_rtp_transport.packets_sent = 1;
hbos0583b282016-11-30 09:50:142993 expected_rtp_transport.bytes_received = 1337;
Artem Titovedacbd52020-07-06 14:06:372994 expected_rtp_transport.packets_received = 4;
hbos7064d592017-01-16 15:38:022995 expected_rtp_transport.dtls_state = RTCDtlsTransportState::kNew;
Philipp Hancke69c1df22022-04-22 13:46:242996 expected_rtp_transport.dtls_role = RTCDtlsRole::kUnknown;
Jonas Oreland149dc722019-08-28 06:10:272997 expected_rtp_transport.selected_candidate_pair_changes = 1;
Philipp Hanckecc1b9b02022-05-04 16:58:262998 expected_rtp_transport.ice_role = RTCIceRole::kUnknown;
Philipp Hancke95b1a342022-05-05 05:53:542999 expected_rtp_transport.ice_local_username_fragment = "thelocalufrag";
Philipp Hancke1f491572022-05-09 15:43:313000 expected_rtp_transport.ice_state = RTCIceTransportState::kNew;
hbos0583b282016-11-30 09:50:143001
hbosdbb64d82016-12-21 09:57:463002 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
hbos0583b282016-11-30 09:50:143003 EXPECT_EQ(
3004 expected_rtp_transport,
3005 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
hbos2fa7c672016-10-24 11:00:053006
3007 cricket::ConnectionInfo rtcp_connection_info;
3008 rtcp_connection_info.best_connection = false;
3009 rtcp_connection_info.local_candidate = *rtcp_local_candidate.get();
3010 rtcp_connection_info.remote_candidate = *rtcp_remote_candidate.get();
3011 rtcp_connection_info.sent_total_bytes = 1337;
3012 rtcp_connection_info.recv_total_bytes = 42;
Artem Titovedacbd52020-07-06 14:06:373013 rtcp_connection_info.sent_total_packets = 3;
3014 rtcp_connection_info.sent_discarded_packets = 2;
3015 rtcp_connection_info.packets_received = 4;
hbos2fa7c672016-10-24 11:00:053016 cricket::TransportChannelStats rtcp_transport_channel_stats;
3017 rtcp_transport_channel_stats.component =
3018 cricket::ICE_CANDIDATE_COMPONENT_RTCP;
Jonas Oreland149dc722019-08-28 06:10:273019 rtcp_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
3020 rtcp_connection_info);
Mirko Bonadei9f6808b2021-05-21 18:46:093021 rtcp_transport_channel_stats.dtls_state = DtlsTransportState::kConnecting;
Jonas Oreland42da5a92022-03-01 12:55:373022 rtcp_transport_channel_stats.ice_transport_stats.bytes_sent = 1337;
3023 rtcp_transport_channel_stats.ice_transport_stats.packets_sent = 1;
3024 rtcp_transport_channel_stats.ice_transport_stats.bytes_received = 42;
3025 rtcp_transport_channel_stats.ice_transport_stats.packets_received = 4;
Philipp Hancke95b1a342022-05-05 05:53:543026 rtcp_transport_channel_stats.ice_transport_stats.ice_local_username_fragment =
3027 "thelocalufrag";
Philipp Hancke1f491572022-05-09 15:43:313028 rtcp_transport_channel_stats.ice_transport_stats.ice_state =
3029 IceTransportState::kChecking;
Steve Anton5b387312018-02-03 00:00:203030 pc_->SetTransportStats(kTransportName, {rtp_transport_channel_stats,
3031 rtcp_transport_channel_stats});
hbos2fa7c672016-10-24 11:00:053032
hbos2fa7c672016-10-24 11:00:053033 // Get stats with RTCP and without an active connection or certificates.
Steve Anton5b387312018-02-03 00:00:203034 report = stats_->GetFreshStatsReport();
hbos0583b282016-11-30 09:50:143035
3036 RTCTransportStats expected_rtcp_transport(
Henrik Boström8dfc90f2022-09-02 07:39:293037 "Ttransport" + rtc::ToString(cricket::ICE_CANDIDATE_COMPONENT_RTCP),
Philipp Hanckeb81823a2023-01-04 14:17:423038 report->timestamp());
hbos0583b282016-11-30 09:50:143039 expected_rtcp_transport.bytes_sent = 1337;
Artem Titovedacbd52020-07-06 14:06:373040 expected_rtcp_transport.packets_sent = 1;
hbos0583b282016-11-30 09:50:143041 expected_rtcp_transport.bytes_received = 42;
Artem Titovedacbd52020-07-06 14:06:373042 expected_rtcp_transport.packets_received = 4;
hbos7064d592017-01-16 15:38:023043 expected_rtcp_transport.dtls_state = RTCDtlsTransportState::kConnecting;
Philipp Hancke69c1df22022-04-22 13:46:243044 expected_rtcp_transport.dtls_role = RTCDtlsRole::kUnknown;
Jonas Oreland149dc722019-08-28 06:10:273045 expected_rtcp_transport.selected_candidate_pair_changes = 0;
Philipp Hanckecc1b9b02022-05-04 16:58:263046 expected_rtcp_transport.ice_role = RTCIceRole::kUnknown;
Philipp Hancke95b1a342022-05-05 05:53:543047 expected_rtcp_transport.ice_local_username_fragment = "thelocalufrag";
Philipp Hancke1f491572022-05-09 15:43:313048 expected_rtcp_transport.ice_state = RTCIceTransportState::kChecking;
hbos0583b282016-11-30 09:50:143049
3050 expected_rtp_transport.rtcp_transport_stats_id = expected_rtcp_transport.id();
hbosdbb64d82016-12-21 09:57:463051 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
hbos0583b282016-11-30 09:50:143052 EXPECT_EQ(
3053 expected_rtp_transport,
3054 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
hbosdbb64d82016-12-21 09:57:463055 ASSERT_TRUE(report->Get(expected_rtcp_transport.id()));
hbos0583b282016-11-30 09:50:143056 EXPECT_EQ(
3057 expected_rtcp_transport,
3058 report->Get(expected_rtcp_transport.id())->cast_to<RTCTransportStats>());
hbos2fa7c672016-10-24 11:00:053059
hbos7064d592017-01-16 15:38:023060 // Get stats with an active connection (selected candidate pair).
Jonas Oreland149dc722019-08-28 06:10:273061 rtcp_transport_channel_stats.ice_transport_stats.connection_infos[0]
3062 .best_connection = true;
Steve Anton5b387312018-02-03 00:00:203063 pc_->SetTransportStats(kTransportName, {rtp_transport_channel_stats,
3064 rtcp_transport_channel_stats});
hbos2fa7c672016-10-24 11:00:053065
Steve Anton5b387312018-02-03 00:00:203066 report = stats_->GetFreshStatsReport();
hbos0583b282016-11-30 09:50:143067
hbos0583b282016-11-30 09:50:143068 expected_rtcp_transport.selected_candidate_pair_id =
Henrik Boström8dfc90f2022-09-02 07:39:293069 "CP" + rtcp_local_candidate->id() + "_" + rtcp_remote_candidate->id();
hbos0583b282016-11-30 09:50:143070
hbosdbb64d82016-12-21 09:57:463071 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
hbos0583b282016-11-30 09:50:143072 EXPECT_EQ(
3073 expected_rtp_transport,
3074 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
hbosdbb64d82016-12-21 09:57:463075 ASSERT_TRUE(report->Get(expected_rtcp_transport.id()));
hbos0583b282016-11-30 09:50:143076 EXPECT_EQ(
3077 expected_rtcp_transport,
3078 report->Get(expected_rtcp_transport.id())->cast_to<RTCTransportStats>());
hbos2fa7c672016-10-24 11:00:053079
3080 // Get stats with certificates.
3081 std::unique_ptr<CertificateInfo> local_certinfo =
Steve Anton5b387312018-02-03 00:00:203082 CreateFakeCertificateAndInfoFromDers({"(local) local", "(local) chain"});
3083 pc_->SetLocalCertificate(kTransportName, local_certinfo->certificate);
hbos2fa7c672016-10-24 11:00:053084 std::unique_ptr<CertificateInfo> remote_certinfo =
3085 CreateFakeCertificateAndInfoFromDers(
Steve Anton5b387312018-02-03 00:00:203086 {"(remote) local", "(remote) chain"});
Taylor Brandstetterc3928662018-02-23 21:04:513087 pc_->SetRemoteCertChain(
Benjamin Wright6c6c9df2018-10-25 08:16:263088 kTransportName,
3089 remote_certinfo->certificate->GetSSLCertificateChain().Clone());
hbos2fa7c672016-10-24 11:00:053090
Steve Anton5b387312018-02-03 00:00:203091 report = stats_->GetFreshStatsReport();
hbos0583b282016-11-30 09:50:143092
3093 expected_rtp_transport.local_certificate_id =
Henrik Boström8dfc90f2022-09-02 07:39:293094 "CF" + local_certinfo->fingerprints[0];
hbos0583b282016-11-30 09:50:143095 expected_rtp_transport.remote_certificate_id =
Henrik Boström8dfc90f2022-09-02 07:39:293096 "CF" + remote_certinfo->fingerprints[0];
hbos0583b282016-11-30 09:50:143097
3098 expected_rtcp_transport.local_certificate_id =
3099 *expected_rtp_transport.local_certificate_id;
3100 expected_rtcp_transport.remote_certificate_id =
3101 *expected_rtp_transport.remote_certificate_id;
3102
hbosdbb64d82016-12-21 09:57:463103 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
hbos0583b282016-11-30 09:50:143104 EXPECT_EQ(
3105 expected_rtp_transport,
3106 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
hbosdbb64d82016-12-21 09:57:463107 ASSERT_TRUE(report->Get(expected_rtcp_transport.id()));
hbos0583b282016-11-30 09:50:143108 EXPECT_EQ(
3109 expected_rtcp_transport,
3110 report->Get(expected_rtcp_transport.id())->cast_to<RTCTransportStats>());
hbos2fa7c672016-10-24 11:00:053111}
3112
Harald Alvestrand5cb78072019-10-28 08:51:173113TEST_F(RTCStatsCollectorTest, CollectRTCTransportStatsWithCrypto) {
3114 const char kTransportName[] = "transport";
3115
3116 pc_->AddVoiceChannel("audio", kTransportName);
3117
3118 std::unique_ptr<cricket::Candidate> rtp_local_candidate =
3119 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
3120 cricket::LOCAL_PORT_TYPE, 42);
3121 std::unique_ptr<cricket::Candidate> rtp_remote_candidate =
3122 CreateFakeCandidate("42.42.42.42", 42, "protocol",
3123 rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
3124 42);
3125 std::unique_ptr<cricket::Candidate> rtcp_local_candidate =
3126 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
3127 cricket::LOCAL_PORT_TYPE, 42);
3128 std::unique_ptr<cricket::Candidate> rtcp_remote_candidate =
3129 CreateFakeCandidate("42.42.42.42", 42, "protocol",
3130 rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
3131 42);
3132
3133 cricket::ConnectionInfo rtp_connection_info;
3134 rtp_connection_info.best_connection = false;
3135 rtp_connection_info.local_candidate = *rtp_local_candidate.get();
3136 rtp_connection_info.remote_candidate = *rtp_remote_candidate.get();
Harald Alvestrand5cb78072019-10-28 08:51:173137 cricket::TransportChannelStats rtp_transport_channel_stats;
3138 rtp_transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
3139 rtp_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
3140 rtp_connection_info);
3141 // The state must be connected in order for crypto parameters to show up.
Mirko Bonadei9f6808b2021-05-21 18:46:093142 rtp_transport_channel_stats.dtls_state = DtlsTransportState::kConnected;
Harald Alvestrand5cb78072019-10-28 08:51:173143 rtp_transport_channel_stats.ice_transport_stats
3144 .selected_candidate_pair_changes = 1;
3145 rtp_transport_channel_stats.ssl_version_bytes = 0x0203;
Philipp Hancke69c1df22022-04-22 13:46:243146 rtp_transport_channel_stats.dtls_role = rtc::SSL_CLIENT;
Philipp Hanckecc1b9b02022-05-04 16:58:263147 rtp_transport_channel_stats.ice_transport_stats.ice_role =
3148 cricket::ICEROLE_CONTROLLING;
Philipp Hancke95b1a342022-05-05 05:53:543149 rtp_transport_channel_stats.ice_transport_stats.ice_local_username_fragment =
3150 "thelocalufrag";
Philipp Hancke1f491572022-05-09 15:43:313151 rtp_transport_channel_stats.ice_transport_stats.ice_state =
3152 IceTransportState::kConnected;
Harald Alvestrand5cb78072019-10-28 08:51:173153 // 0x2F is TLS_RSA_WITH_AES_128_CBC_SHA according to IANA
3154 rtp_transport_channel_stats.ssl_cipher_suite = 0x2F;
Mirko Bonadei7750d802021-07-26 15:27:423155 rtp_transport_channel_stats.srtp_crypto_suite = rtc::kSrtpAes128CmSha1_80;
Harald Alvestrand5cb78072019-10-28 08:51:173156 pc_->SetTransportStats(kTransportName, {rtp_transport_channel_stats});
3157
3158 // Get stats
3159 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3160
3161 RTCTransportStats expected_rtp_transport(
Henrik Boström8dfc90f2022-09-02 07:39:293162 "Ttransport" + rtc::ToString(cricket::ICE_CANDIDATE_COMPONENT_RTP),
Philipp Hanckeb81823a2023-01-04 14:17:423163 report->timestamp());
Harald Alvestrand5cb78072019-10-28 08:51:173164 expected_rtp_transport.dtls_state = RTCDtlsTransportState::kConnected;
3165 expected_rtp_transport.selected_candidate_pair_changes = 1;
Philipp Hanckecc1b9b02022-05-04 16:58:263166 expected_rtp_transport.ice_role = RTCIceRole::kUnknown;
Jonas Oreland42da5a92022-03-01 12:55:373167 expected_rtp_transport.bytes_sent = 0;
3168 expected_rtp_transport.bytes_received = 0;
3169 expected_rtp_transport.packets_sent = 0;
3170 expected_rtp_transport.packets_received = 0;
Philipp Hancke95b1a342022-05-05 05:53:543171 expected_rtp_transport.ice_role = RTCIceRole::kControlling;
3172 expected_rtp_transport.ice_local_username_fragment = "thelocalufrag";
Philipp Hancke1f491572022-05-09 15:43:313173 expected_rtp_transport.ice_state = "connected";
Harald Alvestrand5cb78072019-10-28 08:51:173174 // Crypto parameters
3175 expected_rtp_transport.tls_version = "0203";
Philipp Hancke69c1df22022-04-22 13:46:243176 expected_rtp_transport.dtls_role = RTCDtlsRole::kClient;
Harald Alvestrand5cb78072019-10-28 08:51:173177 expected_rtp_transport.dtls_cipher = "TLS_RSA_WITH_AES_128_CBC_SHA";
3178 expected_rtp_transport.srtp_cipher = "AES_CM_128_HMAC_SHA1_80";
3179
3180 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
3181 EXPECT_EQ(
3182 expected_rtp_transport,
3183 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
3184}
3185
Harald Alvestrand89061872018-01-02 13:08:343186TEST_F(RTCStatsCollectorTest, CollectNoStreamRTCOutboundRTPStreamStats_Audio) {
Harald Alvestrand89061872018-01-02 13:08:343187 cricket::VoiceMediaInfo voice_media_info;
3188
3189 voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
3190 voice_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3191 voice_media_info.senders[0].local_stats[0].ssrc = 1;
3192 voice_media_info.senders[0].packets_sent = 2;
Henrik Boströmaebba7b2022-10-26 14:53:033193 voice_media_info.senders[0].total_packet_send_delay = TimeDelta::Seconds(0.5);
Henrik Boströmcf96e0f2019-04-17 11:51:533194 voice_media_info.senders[0].retransmitted_packets_sent = 20;
Niels Möllerac0a4cb2019-10-09 13:01:333195 voice_media_info.senders[0].payload_bytes_sent = 3;
3196 voice_media_info.senders[0].header_and_padding_bytes_sent = 4;
Henrik Boströmcf96e0f2019-04-17 11:51:533197 voice_media_info.senders[0].retransmitted_bytes_sent = 30;
Jakob Ivarssone91c9922021-07-06 07:55:433198 voice_media_info.senders[0].nacks_rcvd = 31;
Harald Alvestrand89061872018-01-02 13:08:343199 voice_media_info.senders[0].codec_payload_type = 42;
Philipp Hancke684e2412022-07-28 10:41:003200 voice_media_info.senders[0].active = true;
Harald Alvestrand89061872018-01-02 13:08:343201
3202 RtpCodecParameters codec_parameters;
3203 codec_parameters.payload_type = 42;
3204 codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
3205 codec_parameters.name = "dummy";
3206 codec_parameters.clock_rate = 0;
3207 voice_media_info.send_codecs.insert(
3208 std::make_pair(codec_parameters.payload_type, codec_parameters));
3209
Steve Anton5b387312018-02-03 00:00:203210 // Emulates the case where AddTrack is used without an associated MediaStream
Tommi19015512022-02-02 10:49:353211 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Steve Anton5b387312018-02-03 00:00:203212 stats_->SetupLocalTrackAndSender(cricket::MEDIA_TYPE_AUDIO,
Henrik Boström646fda02019-05-22 13:49:423213 "LocalAudioTrackID", 1, false,
3214 /*attachment_id=*/50);
Harald Alvestrand89061872018-01-02 13:08:343215
Steve Anton5b387312018-02-03 00:00:203216 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Harald Alvestrand89061872018-01-02 13:08:343217
Henrik Boströmb43e3bb2022-09-26 10:36:443218 RTCOutboundRTPStreamStats expected_audio("OTTransportName1A1",
Philipp Hanckeb81823a2023-01-04 14:17:423219 report->timestamp());
Henrik Boström8dfc90f2022-09-02 07:39:293220 expected_audio.media_source_id = "SA50";
Henrik Boström1ab61882022-06-16 15:07:333221 expected_audio.mid = "AudioMid";
Harald Alvestrand89061872018-01-02 13:08:343222 expected_audio.ssrc = 1;
Harald Alvestrand89061872018-01-02 13:08:343223 expected_audio.media_type = "audio";
Philipp Hancke3bc01662018-08-28 12:55:033224 expected_audio.kind = "audio";
Henrik Boström15166b22022-10-19 09:06:583225 expected_audio.track_id =
3226 IdForType<DEPRECATED_RTCMediaStreamTrackStats>(report.get());
Henrik Boström8dfc90f2022-09-02 07:39:293227 expected_audio.transport_id = "TTransportName1";
3228 expected_audio.codec_id = "COTTransportName1_42";
Harald Alvestrand89061872018-01-02 13:08:343229 expected_audio.packets_sent = 2;
Henrik Boströmaebba7b2022-10-26 14:53:033230 expected_audio.total_packet_send_delay = 0.5;
Henrik Boströmcf96e0f2019-04-17 11:51:533231 expected_audio.retransmitted_packets_sent = 20;
Harald Alvestrand89061872018-01-02 13:08:343232 expected_audio.bytes_sent = 3;
Niels Möllerac0a4cb2019-10-09 13:01:333233 expected_audio.header_bytes_sent = 4;
Henrik Boströmcf96e0f2019-04-17 11:51:533234 expected_audio.retransmitted_bytes_sent = 30;
Jakob Ivarssone91c9922021-07-06 07:55:433235 expected_audio.nack_count = 31;
Philipp Hancke684e2412022-07-28 10:41:003236 expected_audio.active = true;
Harald Alvestrand89061872018-01-02 13:08:343237
3238 ASSERT_TRUE(report->Get(expected_audio.id()));
3239 EXPECT_EQ(
3240 report->Get(expected_audio.id())->cast_to<RTCOutboundRTPStreamStats>(),
3241 expected_audio);
Harald Alvestrand89061872018-01-02 13:08:343242 EXPECT_TRUE(report->Get(*expected_audio.track_id));
3243 EXPECT_TRUE(report->Get(*expected_audio.transport_id));
3244 EXPECT_TRUE(report->Get(*expected_audio.codec_id));
3245}
3246
Henrik Boström646fda02019-05-22 13:49:423247TEST_F(RTCStatsCollectorTest, RTCAudioSourceStatsCollectedForSenderWithTrack) {
3248 const uint32_t kSsrc = 4;
3249 const int kAttachmentId = 42;
3250
3251 cricket::VoiceMediaInfo voice_media_info;
3252 voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
3253 voice_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3254 voice_media_info.senders[0].local_stats[0].ssrc = kSsrc;
Henrik Boströmd2c336f2019-07-03 15:11:103255 voice_media_info.senders[0].audio_level = 32767; // [0,32767]
3256 voice_media_info.senders[0].total_input_energy = 2.0;
3257 voice_media_info.senders[0].total_input_duration = 3.0;
Taylor Brandstetter64851c02021-06-24 20:32:503258 voice_media_info.senders[0].apm_statistics.echo_return_loss = 42.0;
3259 voice_media_info.senders[0].apm_statistics.echo_return_loss_enhancement =
3260 52.0;
Tommi19015512022-02-02 10:49:353261 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Henrik Boström646fda02019-05-22 13:49:423262 stats_->SetupLocalTrackAndSender(cricket::MEDIA_TYPE_AUDIO,
3263 "LocalAudioTrackID", kSsrc, false,
3264 kAttachmentId);
3265
3266 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3267
Philipp Hanckeb81823a2023-01-04 14:17:423268 RTCAudioSourceStats expected_audio("SA42", report->timestamp());
Henrik Boström646fda02019-05-22 13:49:423269 expected_audio.track_identifier = "LocalAudioTrackID";
3270 expected_audio.kind = "audio";
Henrik Boströmd2c336f2019-07-03 15:11:103271 expected_audio.audio_level = 1.0; // [0,1]
3272 expected_audio.total_audio_energy = 2.0;
3273 expected_audio.total_samples_duration = 3.0;
Taylor Brandstetter64851c02021-06-24 20:32:503274 expected_audio.echo_return_loss = 42.0;
3275 expected_audio.echo_return_loss_enhancement = 52.0;
Henrik Boström646fda02019-05-22 13:49:423276
3277 ASSERT_TRUE(report->Get(expected_audio.id()));
3278 EXPECT_EQ(report->Get(expected_audio.id())->cast_to<RTCAudioSourceStats>(),
3279 expected_audio);
3280}
3281
3282TEST_F(RTCStatsCollectorTest, RTCVideoSourceStatsCollectedForSenderWithTrack) {
3283 const uint32_t kSsrc = 4;
3284 const int kAttachmentId = 42;
3285 const int kVideoSourceWidth = 12;
3286 const int kVideoSourceHeight = 34;
3287
3288 cricket::VideoMediaInfo video_media_info;
Henrik Boströma0ff50c2020-05-05 13:54:463289 video_media_info.aggregated_senders.push_back(cricket::VideoSenderInfo());
Henrik Boström646fda02019-05-22 13:49:423290 video_media_info.senders.push_back(cricket::VideoSenderInfo());
3291 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3292 video_media_info.senders[0].local_stats[0].ssrc = kSsrc;
Byoungchan Leeefe46b62021-11-10 02:23:563293 video_media_info.senders[0].framerate_input = 29.0;
Henrik Boströma0ff50c2020-05-05 13:54:463294 video_media_info.aggregated_senders[0].local_stats.push_back(
3295 cricket::SsrcSenderInfo());
3296 video_media_info.aggregated_senders[0].local_stats[0].ssrc = kSsrc;
Byoungchan Leeefe46b62021-11-10 02:23:563297 video_media_info.aggregated_senders[0].framerate_input = 29.0;
Di Wu668dbf62021-02-27 08:29:153298 video_media_info.aggregated_senders[0].frames = 10001;
Tommi19015512022-02-02 10:49:353299 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström646fda02019-05-22 13:49:423300
3301 auto video_source = FakeVideoTrackSourceForStats::Create(kVideoSourceWidth,
3302 kVideoSourceHeight);
3303 auto video_track = FakeVideoTrackForStats::Create(
3304 "LocalVideoTrackID", MediaStreamTrackInterface::kLive, video_source);
3305 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
3306 cricket::MEDIA_TYPE_VIDEO, video_track, kSsrc, kAttachmentId, {});
Tommi6589def2022-02-17 22:36:473307 EXPECT_CALL(*sender, Stop());
3308 EXPECT_CALL(*sender, SetMediaChannel(_));
Henrik Boström646fda02019-05-22 13:49:423309 pc_->AddSender(sender);
3310
3311 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3312
Philipp Hanckeb81823a2023-01-04 14:17:423313 RTCVideoSourceStats expected_video("SV42", report->timestamp());
Henrik Boström646fda02019-05-22 13:49:423314 expected_video.track_identifier = "LocalVideoTrackID";
3315 expected_video.kind = "video";
3316 expected_video.width = kVideoSourceWidth;
3317 expected_video.height = kVideoSourceHeight;
Byoungchan Leeefe46b62021-11-10 02:23:563318 expected_video.frames_per_second = 29.0;
Di Wu668dbf62021-02-27 08:29:153319 expected_video.frames = 10001;
Henrik Boström646fda02019-05-22 13:49:423320
3321 ASSERT_TRUE(report->Get(expected_video.id()));
3322 EXPECT_EQ(report->Get(expected_video.id())->cast_to<RTCVideoSourceStats>(),
3323 expected_video);
3324}
3325
3326// This test exercises the current behavior and code path, but the correct
3327// behavior is to report frame rate even if we have no SSRC.
3328// TODO(hbos): When we know the frame rate even if we have no SSRC, update the
3329// expectations of this test.
3330TEST_F(RTCStatsCollectorTest,
3331 RTCVideoSourceStatsMissingFrameRateWhenSenderHasNoSsrc) {
3332 // TODO(https://crbug.com/webrtc/8694): When 0 is no longer a magic value for
3333 // "none", update this test.
3334 const uint32_t kNoSsrc = 0;
3335 const int kAttachmentId = 42;
3336 const int kVideoSourceWidth = 12;
3337 const int kVideoSourceHeight = 34;
3338
3339 cricket::VideoMediaInfo video_media_info;
3340 video_media_info.senders.push_back(cricket::VideoSenderInfo());
3341 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
Byoungchan Leeefe46b62021-11-10 02:23:563342 video_media_info.senders[0].framerate_input = 29.0;
Tommi19015512022-02-02 10:49:353343 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström646fda02019-05-22 13:49:423344
3345 auto video_source = FakeVideoTrackSourceForStats::Create(kVideoSourceWidth,
3346 kVideoSourceHeight);
3347 auto video_track = FakeVideoTrackForStats::Create(
3348 "LocalVideoTrackID", MediaStreamTrackInterface::kLive, video_source);
3349 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
3350 cricket::MEDIA_TYPE_VIDEO, video_track, kNoSsrc, kAttachmentId, {});
Tommi6589def2022-02-17 22:36:473351 EXPECT_CALL(*sender, Stop());
3352 EXPECT_CALL(*sender, SetMediaChannel(_));
Henrik Boström646fda02019-05-22 13:49:423353 pc_->AddSender(sender);
3354
3355 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Henrik Boström8dfc90f2022-09-02 07:39:293356 ASSERT_TRUE(report->Get("SV42"));
3357 auto video_stats = report->Get("SV42")->cast_to<RTCVideoSourceStats>();
Henrik Boström646fda02019-05-22 13:49:423358 EXPECT_FALSE(video_stats.frames_per_second.is_defined());
Di Wu668dbf62021-02-27 08:29:153359 EXPECT_FALSE(video_stats.frames.is_defined());
Henrik Boström646fda02019-05-22 13:49:423360}
3361
3362// The track not having a source is not expected to be true in practise, but
3363// this is true in some tests relying on fakes. This test covers that code path.
3364TEST_F(RTCStatsCollectorTest,
3365 RTCVideoSourceStatsMissingResolutionWhenTrackHasNoSource) {
3366 const uint32_t kSsrc = 4;
3367 const int kAttachmentId = 42;
3368
3369 cricket::VideoMediaInfo video_media_info;
3370 video_media_info.senders.push_back(cricket::VideoSenderInfo());
3371 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3372 video_media_info.senders[0].local_stats[0].ssrc = kSsrc;
Byoungchan Leeefe46b62021-11-10 02:23:563373 video_media_info.senders[0].framerate_input = 29.0;
Tommi19015512022-02-02 10:49:353374 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström646fda02019-05-22 13:49:423375
3376 auto video_track = FakeVideoTrackForStats::Create(
3377 "LocalVideoTrackID", MediaStreamTrackInterface::kLive,
3378 /*source=*/nullptr);
3379 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
3380 cricket::MEDIA_TYPE_VIDEO, video_track, kSsrc, kAttachmentId, {});
Tommi6589def2022-02-17 22:36:473381 EXPECT_CALL(*sender, Stop());
3382 EXPECT_CALL(*sender, SetMediaChannel(_));
Henrik Boström646fda02019-05-22 13:49:423383 pc_->AddSender(sender);
3384
3385 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Henrik Boström8dfc90f2022-09-02 07:39:293386 ASSERT_TRUE(report->Get("SV42"));
3387 auto video_stats = report->Get("SV42")->cast_to<RTCVideoSourceStats>();
Henrik Boström646fda02019-05-22 13:49:423388 EXPECT_FALSE(video_stats.width.is_defined());
3389 EXPECT_FALSE(video_stats.height.is_defined());
3390}
3391
3392TEST_F(RTCStatsCollectorTest,
3393 RTCAudioSourceStatsNotCollectedForSenderWithoutTrack) {
3394 const uint32_t kSsrc = 4;
3395 const int kAttachmentId = 42;
3396
3397 cricket::VoiceMediaInfo voice_media_info;
3398 voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
3399 voice_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3400 voice_media_info.senders[0].local_stats[0].ssrc = kSsrc;
Tommi19015512022-02-02 10:49:353401 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Henrik Boström646fda02019-05-22 13:49:423402 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
3403 cricket::MEDIA_TYPE_AUDIO, /*track=*/nullptr, kSsrc, kAttachmentId, {});
Tommi6589def2022-02-17 22:36:473404 EXPECT_CALL(*sender, Stop());
3405 EXPECT_CALL(*sender, SetMediaChannel(_));
Henrik Boström646fda02019-05-22 13:49:423406 pc_->AddSender(sender);
3407
3408 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Henrik Boström8dfc90f2022-09-02 07:39:293409 EXPECT_FALSE(report->Get("SA42"));
Henrik Boström646fda02019-05-22 13:49:423410}
3411
Henrik Boström883eefc2019-05-27 11:40:253412// Parameterized tests on cricket::MediaType (audio or video).
3413class RTCStatsCollectorTestWithParamKind
3414 : public RTCStatsCollectorTest,
3415 public ::testing::WithParamInterface<cricket::MediaType> {
3416 public:
3417 RTCStatsCollectorTestWithParamKind() : media_type_(GetParam()) {
3418 RTC_DCHECK(media_type_ == cricket::MEDIA_TYPE_AUDIO ||
3419 media_type_ == cricket::MEDIA_TYPE_VIDEO);
3420 }
3421
Henrik Boström8dfc90f2022-09-02 07:39:293422 std::string MediaTypeCharStr() const {
Henrik Boström883eefc2019-05-27 11:40:253423 switch (media_type_) {
3424 case cricket::MEDIA_TYPE_AUDIO:
Henrik Boström8dfc90f2022-09-02 07:39:293425 return "A";
Henrik Boström883eefc2019-05-27 11:40:253426 case cricket::MEDIA_TYPE_VIDEO:
Henrik Boström8dfc90f2022-09-02 07:39:293427 return "V";
3428 case cricket::MEDIA_TYPE_DATA:
3429 case cricket::MEDIA_TYPE_UNSUPPORTED:
3430 RTC_DCHECK_NOTREACHED();
3431 return "?";
3432 }
3433 }
3434
3435 std::string MediaTypeKind() const {
3436 switch (media_type_) {
3437 case cricket::MEDIA_TYPE_AUDIO:
3438 return "audio";
3439 case cricket::MEDIA_TYPE_VIDEO:
3440 return "video";
Henrik Boström883eefc2019-05-27 11:40:253441 case cricket::MEDIA_TYPE_DATA:
Philipp Hancke4e8c1152020-10-13 10:43:153442 case cricket::MEDIA_TYPE_UNSUPPORTED:
Artem Titovd3251962021-11-15 15:57:073443 RTC_DCHECK_NOTREACHED();
Henrik Boström883eefc2019-05-27 11:40:253444 return "";
3445 }
3446 }
3447
Henrik Boström883eefc2019-05-27 11:40:253448 // Adds a sender and channel of the appropriate kind, creating a sender info
Artem Titov880fa812021-07-30 20:30:233449 // with the report block's `source_ssrc` and report block data.
Eldar Relloc07e9042020-07-03 08:08:073450 void AddSenderInfoAndMediaChannel(
3451 std::string transport_name,
3452 const std::vector<ReportBlockData>& report_block_datas,
3453 absl::optional<RtpCodecParameters> codec) {
Henrik Boström883eefc2019-05-27 11:40:253454 switch (media_type_) {
3455 case cricket::MEDIA_TYPE_AUDIO: {
3456 cricket::VoiceMediaInfo voice_media_info;
Eldar Relloc07e9042020-07-03 08:08:073457 for (const auto& report_block_data : report_block_datas) {
3458 cricket::VoiceSenderInfo sender;
3459 sender.local_stats.push_back(cricket::SsrcSenderInfo());
3460 sender.local_stats[0].ssrc =
3461 report_block_data.report_block().source_ssrc;
3462 if (codec.has_value()) {
3463 sender.codec_payload_type = codec->payload_type;
3464 voice_media_info.send_codecs.insert(
3465 std::make_pair(codec->payload_type, *codec));
3466 }
3467 sender.report_block_datas.push_back(report_block_data);
3468 voice_media_info.senders.push_back(sender);
Henrik Boström883eefc2019-05-27 11:40:253469 }
Tommi19015512022-02-02 10:49:353470 pc_->AddVoiceChannel("mid", transport_name, voice_media_info);
Henrik Boström883eefc2019-05-27 11:40:253471 return;
3472 }
3473 case cricket::MEDIA_TYPE_VIDEO: {
3474 cricket::VideoMediaInfo video_media_info;
Eldar Relloc07e9042020-07-03 08:08:073475 for (const auto& report_block_data : report_block_datas) {
3476 cricket::VideoSenderInfo sender;
3477 sender.local_stats.push_back(cricket::SsrcSenderInfo());
3478 sender.local_stats[0].ssrc =
3479 report_block_data.report_block().source_ssrc;
3480 if (codec.has_value()) {
3481 sender.codec_payload_type = codec->payload_type;
3482 video_media_info.send_codecs.insert(
3483 std::make_pair(codec->payload_type, *codec));
3484 }
3485 sender.report_block_datas.push_back(report_block_data);
3486 video_media_info.aggregated_senders.push_back(sender);
3487 video_media_info.senders.push_back(sender);
Henrik Boström883eefc2019-05-27 11:40:253488 }
Tommi19015512022-02-02 10:49:353489 pc_->AddVideoChannel("mid", transport_name, video_media_info);
Henrik Boström883eefc2019-05-27 11:40:253490 return;
3491 }
3492 case cricket::MEDIA_TYPE_DATA:
Philipp Hancke4e8c1152020-10-13 10:43:153493 case cricket::MEDIA_TYPE_UNSUPPORTED:
Artem Titovd3251962021-11-15 15:57:073494 RTC_DCHECK_NOTREACHED();
Henrik Boström883eefc2019-05-27 11:40:253495 }
3496 }
3497
3498 protected:
3499 cricket::MediaType media_type_;
3500};
3501
3502// Verifies RTCRemoteInboundRtpStreamStats members that don't require
3503// RTCCodecStats (codecId, jitter) and without setting up an RTCP transport.
3504TEST_P(RTCStatsCollectorTestWithParamKind,
3505 RTCRemoteInboundRtpStreamStatsCollectedFromReportBlock) {
3506 const int64_t kReportBlockTimestampUtcUs = 123456789;
Di Wu86f04ad2021-03-01 07:36:033507 const uint8_t kFractionLost = 12;
Di Wu88a51b22021-03-01 19:22:063508 const int64_t kRoundTripTimeSample1Ms = 1234;
3509 const double kRoundTripTimeSample1Seconds = 1.234;
3510 const int64_t kRoundTripTimeSample2Ms = 13000;
3511 const double kRoundTripTimeSample2Seconds = 13;
Henrik Boström883eefc2019-05-27 11:40:253512
3513 // The report block's timestamp cannot be from the future, set the fake clock
3514 // to match.
Danil Chapovalov0c626af2020-02-10 10:16:003515 fake_clock_.SetTime(Timestamp::Micros(kReportBlockTimestampUtcUs));
Eldar Relloc07e9042020-07-03 08:08:073516 auto ssrcs = {12, 13};
3517 std::vector<ReportBlockData> report_block_datas;
3518 for (auto ssrc : ssrcs) {
3519 RTCPReportBlock report_block;
3520 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
Artem Titov880fa812021-07-30 20:30:233521 // `source_ssrc`, "SSRC of the RTP packet sender".
Eldar Relloc07e9042020-07-03 08:08:073522 report_block.source_ssrc = ssrc;
3523 report_block.packets_lost = 7;
Di Wu86f04ad2021-03-01 07:36:033524 report_block.fraction_lost = kFractionLost;
Eldar Relloc07e9042020-07-03 08:08:073525 ReportBlockData report_block_data;
3526 report_block_data.SetReportBlock(report_block, kReportBlockTimestampUtcUs);
Di Wu88a51b22021-03-01 19:22:063527 report_block_data.AddRoundTripTimeSample(kRoundTripTimeSample1Ms);
Eldar Relloc07e9042020-07-03 08:08:073528 // Only the last sample should be exposed as the
Artem Titovcfea2182021-08-09 23:22:313529 // `RTCRemoteInboundRtpStreamStats::round_trip_time`.
Di Wu88a51b22021-03-01 19:22:063530 report_block_data.AddRoundTripTimeSample(kRoundTripTimeSample2Ms);
Eldar Relloc07e9042020-07-03 08:08:073531 report_block_datas.push_back(report_block_data);
3532 }
3533 AddSenderInfoAndMediaChannel("TransportName", report_block_datas,
Henrik Boström883eefc2019-05-27 11:40:253534 absl::nullopt);
3535
3536 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Eldar Relloc07e9042020-07-03 08:08:073537 for (auto ssrc : ssrcs) {
Henrik Boström8dfc90f2022-09-02 07:39:293538 std::string stream_id = "" + std::to_string(ssrc);
Eldar Relloc07e9042020-07-03 08:08:073539 RTCRemoteInboundRtpStreamStats expected_remote_inbound_rtp(
Philipp Hanckeb81823a2023-01-04 14:17:423540 "RI" + MediaTypeCharStr() + stream_id,
3541 Timestamp::Micros(kReportBlockTimestampUtcUs));
Eldar Relloc07e9042020-07-03 08:08:073542 expected_remote_inbound_rtp.ssrc = ssrc;
Di Wu86f04ad2021-03-01 07:36:033543 expected_remote_inbound_rtp.fraction_lost =
3544 static_cast<double>(kFractionLost) / (1 << 8);
Henrik Boström8dfc90f2022-09-02 07:39:293545 expected_remote_inbound_rtp.kind = MediaTypeKind();
Eldar Relloc07e9042020-07-03 08:08:073546 expected_remote_inbound_rtp.transport_id =
Henrik Boström8dfc90f2022-09-02 07:39:293547 "TTransportName1"; // 1 for RTP (we have no RTCP
3548 // transport)
Eldar Relloc07e9042020-07-03 08:08:073549 expected_remote_inbound_rtp.packets_lost = 7;
Henrik Boströmb43e3bb2022-09-26 10:36:443550 expected_remote_inbound_rtp.local_id =
3551 "OTTransportName1" + MediaTypeCharStr() + stream_id;
Di Wu88a51b22021-03-01 19:22:063552 expected_remote_inbound_rtp.round_trip_time = kRoundTripTimeSample2Seconds;
3553 expected_remote_inbound_rtp.total_round_trip_time =
3554 kRoundTripTimeSample1Seconds + kRoundTripTimeSample2Seconds;
3555 expected_remote_inbound_rtp.round_trip_time_measurements = 2;
Artem Titov880fa812021-07-30 20:30:233556 // This test does not set up RTCCodecStats, so `codec_id` and `jitter` are
Eldar Relloc07e9042020-07-03 08:08:073557 // expected to be missing. These are tested separately.
Henrik Boström883eefc2019-05-27 11:40:253558
Eldar Relloc07e9042020-07-03 08:08:073559 ASSERT_TRUE(report->Get(expected_remote_inbound_rtp.id()));
3560 EXPECT_EQ(report->Get(expected_remote_inbound_rtp.id())
3561 ->cast_to<RTCRemoteInboundRtpStreamStats>(),
3562 expected_remote_inbound_rtp);
3563 EXPECT_TRUE(report->Get(*expected_remote_inbound_rtp.transport_id));
3564 ASSERT_TRUE(report->Get(*expected_remote_inbound_rtp.local_id));
3565 // Lookup works in both directions.
3566 EXPECT_EQ(*report->Get(*expected_remote_inbound_rtp.local_id)
3567 ->cast_to<RTCOutboundRTPStreamStats>()
3568 .remote_id,
3569 expected_remote_inbound_rtp.id());
3570 }
Henrik Boström883eefc2019-05-27 11:40:253571}
3572
3573TEST_P(RTCStatsCollectorTestWithParamKind,
Henrik Boströma3a3b6d2022-11-22 08:56:493574 RTCRemoteInboundRtpStreamStatsRttMissingBeforeMeasurement) {
3575 constexpr int64_t kReportBlockTimestampUtcUs = 123456789;
3576
3577 RTCPReportBlock report_block;
3578 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
3579 // `source_ssrc`, "SSRC of the RTP packet sender".
3580 report_block.source_ssrc = 12;
3581 ReportBlockData report_block_data; // AddRoundTripTimeSample() not called.
3582 report_block_data.SetReportBlock(report_block, kReportBlockTimestampUtcUs);
3583
3584 AddSenderInfoAndMediaChannel("TransportName", {report_block_data},
3585 absl::nullopt);
3586
3587 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3588
3589 std::string remote_inbound_rtp_id = "RI" + MediaTypeCharStr() + "12";
3590 ASSERT_TRUE(report->Get(remote_inbound_rtp_id));
3591 auto& remote_inbound_rtp = report->Get(remote_inbound_rtp_id)
3592 ->cast_to<RTCRemoteInboundRtpStreamStats>();
3593
3594 EXPECT_TRUE(remote_inbound_rtp.round_trip_time_measurements.is_defined());
3595 EXPECT_EQ(0, *remote_inbound_rtp.round_trip_time_measurements);
3596 EXPECT_FALSE(remote_inbound_rtp.round_trip_time.is_defined());
3597}
3598
3599TEST_P(RTCStatsCollectorTestWithParamKind,
Henrik Boström883eefc2019-05-27 11:40:253600 RTCRemoteInboundRtpStreamStatsWithTimestampFromReportBlock) {
3601 const int64_t kReportBlockTimestampUtcUs = 123456789;
Danil Chapovalov0c626af2020-02-10 10:16:003602 fake_clock_.SetTime(Timestamp::Micros(kReportBlockTimestampUtcUs));
Henrik Boström883eefc2019-05-27 11:40:253603
3604 RTCPReportBlock report_block;
Henrik Boström8605fbf2019-06-24 14:44:513605 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
Artem Titov880fa812021-07-30 20:30:233606 // `source_ssrc`, "SSRC of the RTP packet sender".
Henrik Boström883eefc2019-05-27 11:40:253607 report_block.source_ssrc = 12;
3608 ReportBlockData report_block_data;
3609 report_block_data.SetReportBlock(report_block, kReportBlockTimestampUtcUs);
3610
Eldar Relloc07e9042020-07-03 08:08:073611 AddSenderInfoAndMediaChannel("TransportName", {report_block_data},
Henrik Boström883eefc2019-05-27 11:40:253612 absl::nullopt);
3613
3614 // Advance time, it should be OK to have fresher reports than report blocks.
Danil Chapovalov0c626af2020-02-10 10:16:003615 fake_clock_.AdvanceTime(TimeDelta::Micros(1234));
Henrik Boström883eefc2019-05-27 11:40:253616
3617 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3618
Henrik Boström8dfc90f2022-09-02 07:39:293619 std::string remote_inbound_rtp_id = "RI" + MediaTypeCharStr() + "12";
Henrik Boström883eefc2019-05-27 11:40:253620 ASSERT_TRUE(report->Get(remote_inbound_rtp_id));
3621 auto& remote_inbound_rtp = report->Get(remote_inbound_rtp_id)
3622 ->cast_to<RTCRemoteInboundRtpStreamStats>();
3623
3624 // Even though the report time is different, the remote-inbound-rtp timestamp
3625 // is of the time that the report block was received.
Philipp Hanckeb81823a2023-01-04 14:17:423626 EXPECT_EQ(Timestamp::Micros(kReportBlockTimestampUtcUs + 1234),
3627 report->timestamp());
3628 EXPECT_EQ(Timestamp::Micros(kReportBlockTimestampUtcUs),
3629 remote_inbound_rtp.timestamp());
Henrik Boström883eefc2019-05-27 11:40:253630}
3631
3632TEST_P(RTCStatsCollectorTestWithParamKind,
3633 RTCRemoteInboundRtpStreamStatsWithCodecBasedMembers) {
3634 const int64_t kReportBlockTimestampUtcUs = 123456789;
Danil Chapovalov0c626af2020-02-10 10:16:003635 fake_clock_.SetTime(Timestamp::Micros(kReportBlockTimestampUtcUs));
Henrik Boström883eefc2019-05-27 11:40:253636
3637 RTCPReportBlock report_block;
Henrik Boström8605fbf2019-06-24 14:44:513638 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
Artem Titov880fa812021-07-30 20:30:233639 // `source_ssrc`, "SSRC of the RTP packet sender".
Henrik Boström883eefc2019-05-27 11:40:253640 report_block.source_ssrc = 12;
3641 report_block.jitter = 5000;
3642 ReportBlockData report_block_data;
3643 report_block_data.SetReportBlock(report_block, kReportBlockTimestampUtcUs);
3644
3645 RtpCodecParameters codec;
3646 codec.payload_type = 3;
3647 codec.kind = media_type_;
3648 codec.clock_rate = 1000;
3649
Eldar Relloc07e9042020-07-03 08:08:073650 AddSenderInfoAndMediaChannel("TransportName", {report_block_data}, codec);
Henrik Boström883eefc2019-05-27 11:40:253651
3652 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3653
Henrik Boström8dfc90f2022-09-02 07:39:293654 std::string remote_inbound_rtp_id = "RI" + MediaTypeCharStr() + "12";
Henrik Boström883eefc2019-05-27 11:40:253655 ASSERT_TRUE(report->Get(remote_inbound_rtp_id));
3656 auto& remote_inbound_rtp = report->Get(remote_inbound_rtp_id)
3657 ->cast_to<RTCRemoteInboundRtpStreamStats>();
3658
3659 EXPECT_TRUE(remote_inbound_rtp.codec_id.is_defined());
3660 EXPECT_TRUE(report->Get(*remote_inbound_rtp.codec_id));
3661
3662 EXPECT_TRUE(remote_inbound_rtp.jitter.is_defined());
3663 // The jitter (in seconds) is the report block's jitter divided by the codec's
3664 // clock rate.
3665 EXPECT_EQ(5.0, *remote_inbound_rtp.jitter);
3666}
3667
3668TEST_P(RTCStatsCollectorTestWithParamKind,
3669 RTCRemoteInboundRtpStreamStatsWithRtcpTransport) {
3670 const int64_t kReportBlockTimestampUtcUs = 123456789;
Danil Chapovalov0c626af2020-02-10 10:16:003671 fake_clock_.SetTime(Timestamp::Micros(kReportBlockTimestampUtcUs));
Henrik Boström883eefc2019-05-27 11:40:253672
3673 RTCPReportBlock report_block;
Henrik Boström8605fbf2019-06-24 14:44:513674 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
Artem Titov880fa812021-07-30 20:30:233675 // `source_ssrc`, "SSRC of the RTP packet sender".
Henrik Boström883eefc2019-05-27 11:40:253676 report_block.source_ssrc = 12;
3677 ReportBlockData report_block_data;
3678 report_block_data.SetReportBlock(report_block, kReportBlockTimestampUtcUs);
3679
3680 cricket::TransportChannelStats rtp_transport_channel_stats;
3681 rtp_transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
Mirko Bonadei9f6808b2021-05-21 18:46:093682 rtp_transport_channel_stats.dtls_state = DtlsTransportState::kNew;
Henrik Boström883eefc2019-05-27 11:40:253683 cricket::TransportChannelStats rtcp_transport_channel_stats;
3684 rtcp_transport_channel_stats.component =
3685 cricket::ICE_CANDIDATE_COMPONENT_RTCP;
Mirko Bonadei9f6808b2021-05-21 18:46:093686 rtcp_transport_channel_stats.dtls_state = DtlsTransportState::kNew;
Henrik Boström883eefc2019-05-27 11:40:253687 pc_->SetTransportStats("TransportName", {rtp_transport_channel_stats,
3688 rtcp_transport_channel_stats});
Eldar Relloc07e9042020-07-03 08:08:073689 AddSenderInfoAndMediaChannel("TransportName", {report_block_data},
Henrik Boström883eefc2019-05-27 11:40:253690 absl::nullopt);
3691
3692 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3693
Henrik Boström8dfc90f2022-09-02 07:39:293694 std::string remote_inbound_rtp_id = "RI" + MediaTypeCharStr() + "12";
Henrik Boström883eefc2019-05-27 11:40:253695 ASSERT_TRUE(report->Get(remote_inbound_rtp_id));
3696 auto& remote_inbound_rtp = report->Get(remote_inbound_rtp_id)
3697 ->cast_to<RTCRemoteInboundRtpStreamStats>();
3698
3699 EXPECT_TRUE(remote_inbound_rtp.transport_id.is_defined());
Henrik Boström8dfc90f2022-09-02 07:39:293700 EXPECT_EQ("TTransportName2", // 2 for RTCP
Henrik Boström883eefc2019-05-27 11:40:253701 *remote_inbound_rtp.transport_id);
3702 EXPECT_TRUE(report->Get(*remote_inbound_rtp.transport_id));
3703}
3704
Mirko Bonadei1b575412019-09-23 06:34:503705INSTANTIATE_TEST_SUITE_P(All,
Henrik Boström883eefc2019-05-27 11:40:253706 RTCStatsCollectorTestWithParamKind,
3707 ::testing::Values(cricket::MEDIA_TYPE_AUDIO, // "/0"
3708 cricket::MEDIA_TYPE_VIDEO)); // "/1"
3709
Alessio Bazzicaf7b1b952021-03-23 16:23:043710// Checks that no remote outbound stats are collected if not available in
3711// `VoiceMediaInfo`.
3712TEST_F(RTCStatsCollectorTest,
3713 RTCRemoteOutboundRtpAudioStreamStatsNotCollected) {
3714 ExampleStatsGraph graph =
3715 SetupExampleStatsVoiceGraph(/*add_remote_outbound_stats=*/false);
3716 EXPECT_FALSE(graph.full_report->Get(graph.remote_outbound_rtp_id));
3717 // Also check that no other remote outbound report is created (in case the
3718 // expected ID is incorrect).
3719 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3720 ASSERT_NE(report->begin(), report->end())
3721 << "No reports have been generated.";
3722 for (const auto& stats : *report) {
3723 SCOPED_TRACE(stats.id());
3724 EXPECT_NE(stats.type(), RTCRemoteOutboundRtpStreamStats::kType);
3725 }
3726}
3727
3728// Checks that the remote outbound stats are collected when available in
3729// `VoiceMediaInfo`.
3730TEST_F(RTCStatsCollectorTest, RTCRemoteOutboundRtpAudioStreamStatsCollected) {
3731 ExampleStatsGraph graph =
3732 SetupExampleStatsVoiceGraph(/*add_remote_outbound_stats=*/true);
3733 ASSERT_TRUE(graph.full_report->Get(graph.remote_outbound_rtp_id));
3734 const auto& remote_outbound_rtp =
3735 graph.full_report->Get(graph.remote_outbound_rtp_id)
3736 ->cast_to<RTCRemoteOutboundRtpStreamStats>();
Philipp Hanckeb81823a2023-01-04 14:17:423737 EXPECT_EQ(remote_outbound_rtp.timestamp(),
3738 Timestamp::Millis(kRemoteOutboundStatsTimestampMs));
Alessio Bazzicaf7b1b952021-03-23 16:23:043739 EXPECT_FLOAT_EQ(*remote_outbound_rtp.remote_timestamp,
3740 static_cast<double>(kRemoteOutboundStatsRemoteTimestampMs));
3741 EXPECT_EQ(*remote_outbound_rtp.packets_sent, kRemoteOutboundStatsPacketsSent);
3742 EXPECT_EQ(*remote_outbound_rtp.bytes_sent, kRemoteOutboundStatsBytesSent);
3743 EXPECT_EQ(*remote_outbound_rtp.reports_sent,
3744 kRemoteOutboundStatsReportsCount);
3745}
3746
Henrik Boström646fda02019-05-22 13:49:423747TEST_F(RTCStatsCollectorTest,
3748 RTCVideoSourceStatsNotCollectedForSenderWithoutTrack) {
3749 const uint32_t kSsrc = 4;
3750 const int kAttachmentId = 42;
3751
3752 cricket::VideoMediaInfo video_media_info;
3753 video_media_info.senders.push_back(cricket::VideoSenderInfo());
3754 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3755 video_media_info.senders[0].local_stats[0].ssrc = kSsrc;
Byoungchan Leeefe46b62021-11-10 02:23:563756 video_media_info.senders[0].framerate_input = 29.0;
Tommi19015512022-02-02 10:49:353757 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström646fda02019-05-22 13:49:423758
3759 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
3760 cricket::MEDIA_TYPE_VIDEO, /*track=*/nullptr, kSsrc, kAttachmentId, {});
Tommi6589def2022-02-17 22:36:473761 EXPECT_CALL(*sender, Stop());
3762 EXPECT_CALL(*sender, SetMediaChannel(_));
Henrik Boström646fda02019-05-22 13:49:423763 pc_->AddSender(sender);
3764
3765 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Henrik Boström8dfc90f2022-09-02 07:39:293766 EXPECT_FALSE(report->Get("SV42"));
Henrik Boström646fda02019-05-22 13:49:423767}
3768
Taylor Brandstetter64851c02021-06-24 20:32:503769// Test collecting echo return loss stats from the audio processor attached to
3770// the track, rather than the voice sender info.
3771TEST_F(RTCStatsCollectorTest, CollectEchoReturnLossFromTrackAudioProcessor) {
3772 rtc::scoped_refptr<MediaStream> local_stream =
3773 MediaStream::Create("LocalStreamId");
3774 pc_->mutable_local_streams()->AddStream(local_stream);
3775
3776 // Local audio track
3777 rtc::scoped_refptr<MediaStreamTrackInterface> local_audio_track =
3778 CreateFakeTrack(cricket::MEDIA_TYPE_AUDIO, "LocalAudioTrackID",
3779 MediaStreamTrackInterface::kEnded,
3780 /*create_fake_audio_processor=*/true);
Harald Alvestrand2f7ad282022-04-21 11:35:433781 local_stream->AddTrack(rtc::scoped_refptr<AudioTrackInterface>(
3782 static_cast<AudioTrackInterface*>(local_audio_track.get())));
Taylor Brandstetter64851c02021-06-24 20:32:503783
3784 cricket::VoiceSenderInfo voice_sender_info_ssrc1;
3785 voice_sender_info_ssrc1.local_stats.push_back(cricket::SsrcSenderInfo());
3786 voice_sender_info_ssrc1.local_stats[0].ssrc = 1;
3787
3788 stats_->CreateMockRtpSendersReceiversAndChannels(
3789 {std::make_pair(local_audio_track.get(), voice_sender_info_ssrc1)}, {},
3790 {}, {}, {local_stream->id()}, {});
3791
3792 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3793
Henrik Boström15166b22022-10-19 09:06:583794 DEPRECATED_RTCMediaStreamTrackStats expected_local_audio_track_ssrc1(
3795 IdForType<DEPRECATED_RTCMediaStreamTrackStats>(report.get()),
Philipp Hanckeb81823a2023-01-04 14:17:423796 report->timestamp(), RTCMediaStreamTrackKind::kAudio);
Taylor Brandstetter64851c02021-06-24 20:32:503797 expected_local_audio_track_ssrc1.track_identifier = local_audio_track->id();
3798 expected_local_audio_track_ssrc1.media_source_id =
Henrik Boström8dfc90f2022-09-02 07:39:293799 "SA11"; // Attachment ID = SSRC + 10
Taylor Brandstetter64851c02021-06-24 20:32:503800 expected_local_audio_track_ssrc1.remote_source = false;
3801 expected_local_audio_track_ssrc1.ended = true;
3802 expected_local_audio_track_ssrc1.detached = false;
3803 expected_local_audio_track_ssrc1.echo_return_loss = 2.0;
3804 expected_local_audio_track_ssrc1.echo_return_loss_enhancement = 3.0;
3805 ASSERT_TRUE(report->Get(expected_local_audio_track_ssrc1.id()))
3806 << "Did not find " << expected_local_audio_track_ssrc1.id() << " in "
3807 << report->ToJson();
3808 EXPECT_EQ(expected_local_audio_track_ssrc1,
3809 report->Get(expected_local_audio_track_ssrc1.id())
Henrik Boström15166b22022-10-19 09:06:583810 ->cast_to<DEPRECATED_RTCMediaStreamTrackStats>());
Taylor Brandstetter64851c02021-06-24 20:32:503811
Philipp Hanckeb81823a2023-01-04 14:17:423812 RTCAudioSourceStats expected_audio("SA11", report->timestamp());
Taylor Brandstetter64851c02021-06-24 20:32:503813 expected_audio.track_identifier = "LocalAudioTrackID";
3814 expected_audio.kind = "audio";
3815 expected_audio.audio_level = 0;
3816 expected_audio.total_audio_energy = 0;
3817 expected_audio.total_samples_duration = 0;
3818 expected_audio.echo_return_loss = 2.0;
3819 expected_audio.echo_return_loss_enhancement = 3.0;
3820
3821 ASSERT_TRUE(report->Get(expected_audio.id()));
3822 EXPECT_EQ(report->Get(expected_audio.id())->cast_to<RTCAudioSourceStats>(),
3823 expected_audio);
3824}
3825
Henrik Boström5b3541f2018-03-19 12:52:563826TEST_F(RTCStatsCollectorTest, GetStatsWithSenderSelector) {
3827 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
3828 // Expected stats graph when filtered by sender:
3829 //
Henrik Boström646fda02019-05-22 13:49:423830 // +--- track (sender)
3831 // | ^
3832 // | |
3833 // | +--------- outbound-rtp
3834 // | | | |
3835 // | | v v
3836 // | | codec (send) transport
3837 // v v
3838 // media-source
Henrik Boström5b3541f2018-03-19 12:52:563839 rtc::scoped_refptr<const RTCStatsReport> sender_report =
3840 stats_->GetStatsReportWithSenderSelector(graph.sender);
3841 EXPECT_TRUE(sender_report);
Philipp Hanckeb81823a2023-01-04 14:17:423842 EXPECT_EQ(sender_report->timestamp(), graph.full_report->timestamp());
Henrik Boström646fda02019-05-22 13:49:423843 EXPECT_EQ(sender_report->size(), 5u);
Henrik Boström5b3541f2018-03-19 12:52:563844 EXPECT_TRUE(sender_report->Get(graph.send_codec_id));
3845 EXPECT_FALSE(sender_report->Get(graph.recv_codec_id));
3846 EXPECT_TRUE(sender_report->Get(graph.outbound_rtp_id));
3847 EXPECT_FALSE(sender_report->Get(graph.inbound_rtp_id));
3848 EXPECT_TRUE(sender_report->Get(graph.transport_id));
3849 EXPECT_TRUE(sender_report->Get(graph.sender_track_id));
3850 EXPECT_FALSE(sender_report->Get(graph.receiver_track_id));
3851 EXPECT_FALSE(sender_report->Get(graph.remote_stream_id));
3852 EXPECT_FALSE(sender_report->Get(graph.peer_connection_id));
Henrik Boström646fda02019-05-22 13:49:423853 EXPECT_TRUE(sender_report->Get(graph.media_source_id));
Henrik Boström5b3541f2018-03-19 12:52:563854}
3855
3856TEST_F(RTCStatsCollectorTest, GetStatsWithReceiverSelector) {
3857 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
3858 // Expected stats graph when filtered by receiver:
3859 //
Henrik Boström646fda02019-05-22 13:49:423860 // track (receiver)
3861 // ^
3862 // |
3863 // inbound-rtp ---------------+
3864 // | |
3865 // v v
3866 // transport codec (recv)
Henrik Boström5b3541f2018-03-19 12:52:563867 rtc::scoped_refptr<const RTCStatsReport> receiver_report =
3868 stats_->GetStatsReportWithReceiverSelector(graph.receiver);
3869 EXPECT_TRUE(receiver_report);
3870 EXPECT_EQ(receiver_report->size(), 4u);
Philipp Hanckeb81823a2023-01-04 14:17:423871 EXPECT_EQ(receiver_report->timestamp(), graph.full_report->timestamp());
Henrik Boström5b3541f2018-03-19 12:52:563872 EXPECT_FALSE(receiver_report->Get(graph.send_codec_id));
3873 EXPECT_TRUE(receiver_report->Get(graph.recv_codec_id));
3874 EXPECT_FALSE(receiver_report->Get(graph.outbound_rtp_id));
3875 EXPECT_TRUE(receiver_report->Get(graph.inbound_rtp_id));
3876 EXPECT_TRUE(receiver_report->Get(graph.transport_id));
3877 EXPECT_FALSE(receiver_report->Get(graph.sender_track_id));
3878 EXPECT_TRUE(receiver_report->Get(graph.receiver_track_id));
3879 EXPECT_FALSE(receiver_report->Get(graph.remote_stream_id));
3880 EXPECT_FALSE(receiver_report->Get(graph.peer_connection_id));
Henrik Boström646fda02019-05-22 13:49:423881 EXPECT_FALSE(receiver_report->Get(graph.media_source_id));
Henrik Boström5b3541f2018-03-19 12:52:563882}
3883
3884TEST_F(RTCStatsCollectorTest, GetStatsWithNullSenderSelector) {
3885 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
3886 rtc::scoped_refptr<const RTCStatsReport> empty_report =
3887 stats_->GetStatsReportWithSenderSelector(nullptr);
3888 EXPECT_TRUE(empty_report);
Philipp Hanckeb81823a2023-01-04 14:17:423889 EXPECT_EQ(empty_report->timestamp(), graph.full_report->timestamp());
Henrik Boström5b3541f2018-03-19 12:52:563890 EXPECT_EQ(empty_report->size(), 0u);
3891}
3892
3893TEST_F(RTCStatsCollectorTest, GetStatsWithNullReceiverSelector) {
3894 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
3895 rtc::scoped_refptr<const RTCStatsReport> empty_report =
3896 stats_->GetStatsReportWithReceiverSelector(nullptr);
3897 EXPECT_TRUE(empty_report);
Philipp Hanckeb81823a2023-01-04 14:17:423898 EXPECT_EQ(empty_report->timestamp(), graph.full_report->timestamp());
Henrik Boström5b3541f2018-03-19 12:52:563899 EXPECT_EQ(empty_report->size(), 0u);
3900}
3901
Henrik Boström5ed4da72022-12-24 10:20:123902// Before SetLocalDescription() senders don't have an SSRC.
3903// To simulate this case we create a mock sender with SSRC=0.
3904TEST_F(RTCStatsCollectorTest, RtpIsMissingWhileSsrcIsZero) {
Harald Alvestrand89061872018-01-02 13:08:343905 rtc::scoped_refptr<MediaStreamTrackInterface> track =
3906 CreateFakeTrack(cricket::MEDIA_TYPE_AUDIO, "audioTrack",
3907 MediaStreamTrackInterface::kLive);
Steve Anton57858b32018-02-15 23:19:503908 rtc::scoped_refptr<MockRtpSenderInternal> sender =
Henrik Boström646fda02019-05-22 13:49:423909 CreateMockSender(cricket::MEDIA_TYPE_AUDIO, track, 0, 49, {});
Tommi6589def2022-02-17 22:36:473910 EXPECT_CALL(*sender, Stop());
Steve Anton5b387312018-02-03 00:00:203911 pc_->AddSender(sender);
3912
3913 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3914
Henrik Boström5ed4da72022-12-24 10:20:123915 auto tracks = report->GetStatsOfType<DEPRECATED_RTCMediaStreamTrackStats>();
3916 EXPECT_EQ(1U, tracks.size());
3917 auto outbound_rtps = report->GetStatsOfType<RTCOutboundRTPStreamStats>();
3918 EXPECT_TRUE(outbound_rtps.empty());
Harald Alvestrand89061872018-01-02 13:08:343919}
3920
Henrik Boström5ed4da72022-12-24 10:20:123921// We may also be in a case where the SSRC has been assigned but no
3922// `voice_sender_info` stats exist yet.
3923TEST_F(RTCStatsCollectorTest, DoNotCrashIfSsrcIsKnownButInfosAreStillMissing) {
Harald Alvestrand76d29522018-01-30 13:43:293924 rtc::scoped_refptr<MediaStreamTrackInterface> track =
3925 CreateFakeTrack(cricket::MEDIA_TYPE_AUDIO, "audioTrack",
3926 MediaStreamTrackInterface::kLive);
Steve Anton57858b32018-02-15 23:19:503927 rtc::scoped_refptr<MockRtpSenderInternal> sender =
Henrik Boström646fda02019-05-22 13:49:423928 CreateMockSender(cricket::MEDIA_TYPE_AUDIO, track, 4711, 49, {});
Tommi6589def2022-02-17 22:36:473929 EXPECT_CALL(*sender, Stop());
Steve Anton5b387312018-02-03 00:00:203930 pc_->AddSender(sender);
3931
Harald Alvestrand76d29522018-01-30 13:43:293932 // We do not generate any matching voice_sender_info stats.
Steve Anton5b387312018-02-03 00:00:203933 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3934
Henrik Boström15166b22022-10-19 09:06:583935 std::vector<const DEPRECATED_RTCMediaStreamTrackStats*> track_stats =
3936 report->GetStatsOfType<DEPRECATED_RTCMediaStreamTrackStats>();
Mirko Bonadeie12c1fe2018-07-03 10:53:233937 EXPECT_EQ(1U, track_stats.size());
Henrik Boström5ed4da72022-12-24 10:20:123938 auto outbound_rtps = report->GetStatsOfType<RTCOutboundRTPStreamStats>();
3939 EXPECT_TRUE(outbound_rtps.empty());
Harald Alvestrand76d29522018-01-30 13:43:293940}
3941
Taylor Brandstetter87d5a742018-03-06 17:42:253942// Used for test below, to test calling GetStatsReport during a callback.
Taylor Brandstetter25e022f2018-03-08 17:53:473943class RecursiveCallback : public RTCStatsCollectorCallback {
Taylor Brandstetter87d5a742018-03-06 17:42:253944 public:
Taylor Brandstetter25e022f2018-03-08 17:53:473945 explicit RecursiveCallback(RTCStatsCollectorWrapper* stats) : stats_(stats) {}
Taylor Brandstetter87d5a742018-03-06 17:42:253946
3947 void OnStatsDelivered(
3948 const rtc::scoped_refptr<const RTCStatsReport>& report) override {
3949 stats_->GetStatsReport();
3950 called_ = true;
3951 }
3952
3953 bool called() const { return called_; }
3954
3955 private:
3956 RTCStatsCollectorWrapper* stats_;
3957 bool called_ = false;
3958};
3959
3960// Test that nothing bad happens if a callback causes GetStatsReport to be
3961// called again recursively. Regression test for crbug.com/webrtc/8973.
Taylor Brandstetter25e022f2018-03-08 17:53:473962TEST_F(RTCStatsCollectorTest, DoNotCrashWhenGetStatsCalledDuringCallback) {
Niels Möller027c7932022-01-25 12:56:073963 auto callback1 = rtc::make_ref_counted<RecursiveCallback>(stats_.get());
3964 auto callback2 = rtc::make_ref_counted<RecursiveCallback>(stats_.get());
Taylor Brandstetter87d5a742018-03-06 17:42:253965 stats_->stats_collector()->GetStatsReport(callback1);
3966 stats_->stats_collector()->GetStatsReport(callback2);
3967 EXPECT_TRUE_WAIT(callback1->called(), kGetStatsReportTimeoutMs);
3968 EXPECT_TRUE_WAIT(callback2->called(), kGetStatsReportTimeoutMs);
3969}
3970
Steve Anton5b387312018-02-03 00:00:203971class RTCTestStats : public RTCStats {
hbosc82f2e12016-09-05 08:36:503972 public:
Steve Anton5b387312018-02-03 00:00:203973 WEBRTC_RTCSTATS_DECL();
3974
Philipp Hanckeb81823a2023-01-04 14:17:423975 RTCTestStats(const std::string& id, Timestamp timestamp)
3976 : RTCStats(id, timestamp), dummy_stat("dummyStat") {}
Steve Anton5b387312018-02-03 00:00:203977
3978 RTCStatsMember<int32_t> dummy_stat;
3979};
3980
Mirko Bonadeic4dd7302019-02-25 08:12:023981WEBRTC_RTCSTATS_IMPL(RTCTestStats, RTCStats, "test-stats", &dummy_stat)
Steve Anton5b387312018-02-03 00:00:203982
3983// Overrides the stats collection to verify thread usage and that the resulting
3984// partial reports are merged.
3985class FakeRTCStatsCollector : public RTCStatsCollector,
3986 public RTCStatsCollectorCallback {
3987 public:
3988 static rtc::scoped_refptr<FakeRTCStatsCollector> Create(
3989 PeerConnectionInternal* pc,
3990 int64_t cache_lifetime_us) {
Niels Möllere7cc8832022-01-04 14:20:033991 return rtc::scoped_refptr<FakeRTCStatsCollector>(
3992 new rtc::RefCountedObject<FakeRTCStatsCollector>(pc,
3993 cache_lifetime_us));
Steve Anton5b387312018-02-03 00:00:203994 }
3995
Tomas Gunnarssone6de5ae2021-04-22 16:16:353996 // Since FakeRTCStatsCollector inherits twice from RefCountInterface, once via
3997 // RTCStatsCollector and once via RTCStatsCollectorCallback, scoped_refptr
3998 // will get confused about which AddRef()/Release() methods to call.
3999 // So to remove all doubt, we declare them here again in the class that we
4000 // give to scoped_refptr.
4001 // Satisfying the implementation of these methods and associating them with a
4002 // reference counter, will be done by RefCountedObject.
4003 virtual void AddRef() const = 0;
4004 virtual rtc::RefCountReleaseStatus Release() const = 0;
4005
Steve Anton5b387312018-02-03 00:00:204006 // RTCStatsCollectorCallback implementation.
4007 void OnStatsDelivered(
4008 const rtc::scoped_refptr<const RTCStatsReport>& report) override {
4009 EXPECT_TRUE(signaling_thread_->IsCurrent());
Markus Handell6fcd0f82020-07-07 17:08:534010 MutexLock lock(&lock_);
Steve Anton5b387312018-02-03 00:00:204011 delivered_report_ = report;
4012 }
4013
4014 void VerifyThreadUsageAndResultsMerging() {
4015 GetStatsReport(rtc::scoped_refptr<RTCStatsCollectorCallback>(this));
4016 EXPECT_TRUE_WAIT(HasVerifiedResults(), kGetStatsReportTimeoutMs);
4017 }
4018
4019 bool HasVerifiedResults() {
4020 EXPECT_TRUE(signaling_thread_->IsCurrent());
Markus Handell6fcd0f82020-07-07 17:08:534021 MutexLock lock(&lock_);
Steve Anton5b387312018-02-03 00:00:204022 if (!delivered_report_)
4023 return false;
4024 EXPECT_EQ(produced_on_signaling_thread_, 1);
4025 EXPECT_EQ(produced_on_network_thread_, 1);
4026
4027 EXPECT_TRUE(delivered_report_->Get("SignalingThreadStats"));
4028 EXPECT_TRUE(delivered_report_->Get("NetworkThreadStats"));
4029
4030 produced_on_signaling_thread_ = 0;
4031 produced_on_network_thread_ = 0;
4032 delivered_report_ = nullptr;
4033 return true;
hbosc82f2e12016-09-05 08:36:504034 }
4035
4036 protected:
Steve Anton5b387312018-02-03 00:00:204037 FakeRTCStatsCollector(PeerConnectionInternal* pc, int64_t cache_lifetime)
4038 : RTCStatsCollector(pc, cache_lifetime),
4039 signaling_thread_(pc->signaling_thread()),
4040 worker_thread_(pc->worker_thread()),
4041 network_thread_(pc->network_thread()) {}
4042
Henrik Boström40b030e2019-02-28 08:49:314043 void ProducePartialResultsOnSignalingThreadImpl(
Philipp Hanckeb81823a2023-01-04 14:17:424044 Timestamp timestamp,
Henrik Boström40b030e2019-02-28 08:49:314045 RTCStatsReport* partial_report) override {
Steve Anton5b387312018-02-03 00:00:204046 EXPECT_TRUE(signaling_thread_->IsCurrent());
4047 {
Markus Handell6fcd0f82020-07-07 17:08:534048 MutexLock lock(&lock_);
Steve Anton5b387312018-02-03 00:00:204049 EXPECT_FALSE(delivered_report_);
4050 ++produced_on_signaling_thread_;
4051 }
4052
Henrik Boström40b030e2019-02-28 08:49:314053 partial_report->AddStats(std::unique_ptr<const RTCStats>(
Philipp Hanckeb81823a2023-01-04 14:17:424054 new RTCTestStats("SignalingThreadStats", timestamp)));
Steve Anton5b387312018-02-03 00:00:204055 }
Henrik Boström40b030e2019-02-28 08:49:314056 void ProducePartialResultsOnNetworkThreadImpl(
Philipp Hanckeb81823a2023-01-04 14:17:424057 Timestamp timestamp,
Henrik Boström40b030e2019-02-28 08:49:314058 const std::map<std::string, cricket::TransportStats>&
4059 transport_stats_by_name,
4060 const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
4061 RTCStatsReport* partial_report) override {
Steve Anton5b387312018-02-03 00:00:204062 EXPECT_TRUE(network_thread_->IsCurrent());
4063 {
Markus Handell6fcd0f82020-07-07 17:08:534064 MutexLock lock(&lock_);
Steve Anton5b387312018-02-03 00:00:204065 EXPECT_FALSE(delivered_report_);
4066 ++produced_on_network_thread_;
4067 }
4068
Henrik Boström40b030e2019-02-28 08:49:314069 partial_report->AddStats(std::unique_ptr<const RTCStats>(
Philipp Hanckeb81823a2023-01-04 14:17:424070 new RTCTestStats("NetworkThreadStats", timestamp)));
Steve Anton5b387312018-02-03 00:00:204071 }
4072
4073 private:
4074 rtc::Thread* const signaling_thread_;
4075 rtc::Thread* const worker_thread_;
4076 rtc::Thread* const network_thread_;
4077
Markus Handell6fcd0f82020-07-07 17:08:534078 Mutex lock_;
Steve Anton5b387312018-02-03 00:00:204079 rtc::scoped_refptr<const RTCStatsReport> delivered_report_;
4080 int produced_on_signaling_thread_ = 0;
4081 int produced_on_network_thread_ = 0;
hbosc82f2e12016-09-05 08:36:504082};
4083
Steve Anton5b387312018-02-03 00:00:204084TEST(RTCStatsCollectorTestWithFakeCollector, ThreadUsageAndResultsMerging) {
Niels Möller83830f32022-05-20 07:12:574085 rtc::AutoThread main_thread_;
Niels Möller027c7932022-01-25 12:56:074086 auto pc = rtc::make_ref_counted<FakePeerConnectionForStats>();
Steve Anton5b387312018-02-03 00:00:204087 rtc::scoped_refptr<FakeRTCStatsCollector> stats_collector(
Niels Möllerafb246b2022-04-20 12:26:504088 FakeRTCStatsCollector::Create(pc.get(),
4089 50 * rtc::kNumMicrosecsPerMillisec));
Steve Anton5b387312018-02-03 00:00:204090 stats_collector->VerifyThreadUsageAndResultsMerging();
hbosc82f2e12016-09-05 08:36:504091}
4092
4093} // namespace
4094
hbosd565b732016-08-30 21:04:354095} // namespace webrtc