blob: 17f706f0cad281596ef82ec2571164718b3070e0 [file] [log] [blame]
hbosd565b732016-08-30 14:04:35 -07001/*
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 19:08:33 +020011#include "pc/rtc_stats_collector.h"
12
Henrik Boström883eefc2019-05-27 13:40:25 +020013#include <ctype.h>
Harald Alvestrandc24a2182022-02-23 13:44:59 +000014#include <stddef.h>
15#include <stdint.h>
Henrik Boström883eefc2019-05-27 13:40:25 +020016
17#include <algorithm>
hbos9e302742017-01-20 02:47:10 -080018#include <initializer_list>
hbosd565b732016-08-30 14:04:35 -070019#include <memory>
hbosda389e32016-10-25 10:55:08 -070020#include <ostream>
hbosd565b732016-08-30 14:04:35 -070021#include <string>
Harald Alvestrandc24a2182022-02-23 13:44:59 +000022#include <type_traits>
Steve Anton36b29d12017-10-30 09:57:42 -070023#include <utility>
hbosd565b732016-08-30 14:04:35 -070024#include <vector>
25
Steve Anton1c9c9fc2019-02-14 15:13:09 -080026#include "absl/strings/str_replace.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000027#include "api/candidate.h"
Mirko Bonadei9f6808b2021-05-21 20:46:09 +020028#include "api/dtls_transport_interface.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000029#include "api/media_stream_interface.h"
Harald Alvestrand9cb42c82020-10-11 13:03:47 +000030#include "api/media_stream_track.h"
Steve Anton10542f22019-01-11 09:11:00 -080031#include "api/rtp_parameters.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000032#include "api/stats/rtc_stats.h"
Steve Anton10542f22019-01-11 09:11:00 -080033#include "api/stats/rtc_stats_report.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020034#include "api/stats/rtcstats_objects.h"
Sebastian Jansson5f83cf02018-05-08 14:52:22 +020035#include "api/units/time_delta.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000036#include "api/units/timestamp.h"
37#include "api/video/recordable_encoded_frame.h"
38#include "api/video/video_content_type.h"
39#include "api/video/video_frame.h"
40#include "api/video/video_sink_interface.h"
41#include "api/video/video_source_interface.h"
42#include "common_video/include/quality_limitation_reason.h"
43#include "media/base/media_channel.h"
44#include "modules/audio_processing/include/audio_processing_statistics.h"
Henrik Boström883eefc2019-05-27 13:40:25 +020045#include "modules/rtp_rtcp/include/report_block_data.h"
46#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000047#include "p2p/base/connection_info.h"
48#include "p2p/base/ice_transport_internal.h"
Steve Anton10542f22019-01-11 09:11:00 -080049#include "p2p/base/p2p_constants.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020050#include "p2p/base/port.h"
Steve Anton10542f22019-01-11 09:11:00 -080051#include "pc/media_stream.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000052#include "pc/stream_collection.h"
Taylor Brandstetter3a034e12020-07-09 15:32:34 -070053#include "pc/test/fake_data_channel_provider.h"
Steve Anton10542f22019-01-11 09:11:00 -080054#include "pc/test/fake_peer_connection_for_stats.h"
55#include "pc/test/mock_data_channel.h"
56#include "pc/test/mock_rtp_receiver_internal.h"
57#include "pc/test/mock_rtp_sender_internal.h"
58#include "pc/test/rtc_stats_obtainer.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020059#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080060#include "rtc_base/fake_clock.h"
61#include "rtc_base/fake_ssl_identity.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020062#include "rtc_base/gunit.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000063#include "rtc_base/network_constants.h"
64#include "rtc_base/ref_counted_object.h"
65#include "rtc_base/rtc_certificate.h"
66#include "rtc_base/socket_address.h"
67#include "rtc_base/ssl_fingerprint.h"
68#include "rtc_base/ssl_identity.h"
69#include "rtc_base/ssl_stream_adapter.h"
70#include "rtc_base/string_encode.h"
Harald Alvestrand910cdc22020-01-09 12:58:23 +010071#include "rtc_base/strings/json.h"
Markus Handell6fcd0f82020-07-07 19:08:53 +020072#include "rtc_base/synchronization/mutex.h"
Steve Anton10542f22019-01-11 09:11:00 -080073#include "rtc_base/time_utils.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000074#include "test/gmock.h"
75#include "test/gtest.h"
hbosd565b732016-08-30 14:04:35 -070076
Alessio Bazzica049e6112021-03-18 12:55:11 +010077using ::testing::_;
Mirko Bonadei6a489f22019-04-09 15:11:12 +020078using ::testing::AtLeast;
79using ::testing::Invoke;
80using ::testing::Return;
hbosd565b732016-08-30 14:04:35 -070081
82namespace webrtc {
83
Artem Titov880fa812021-07-30 22:30:23 +020084// These are used by gtest code, such as if `EXPECT_EQ` fails.
hbosda389e32016-10-25 10:55:08 -070085void PrintTo(const RTCCertificateStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 07:29:12 -070086 *os << stats.ToJson();
hbosda389e32016-10-25 10:55:08 -070087}
88
hbos0adb8282016-11-23 02:32:06 -080089void PrintTo(const RTCCodecStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 07:29:12 -070090 *os << stats.ToJson();
hbos0adb8282016-11-23 02:32:06 -080091}
92
hbosda389e32016-10-25 10:55:08 -070093void PrintTo(const RTCDataChannelStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 07:29:12 -070094 *os << stats.ToJson();
hbosda389e32016-10-25 10:55:08 -070095}
96
97void PrintTo(const RTCIceCandidatePairStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 07:29:12 -070098 *os << stats.ToJson();
hbosda389e32016-10-25 10:55:08 -070099}
100
101void PrintTo(const RTCLocalIceCandidateStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 07:29:12 -0700102 *os << stats.ToJson();
hbosda389e32016-10-25 10:55:08 -0700103}
104
105void PrintTo(const RTCRemoteIceCandidateStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 07:29:12 -0700106 *os << stats.ToJson();
hbosda389e32016-10-25 10:55:08 -0700107}
108
109void PrintTo(const RTCPeerConnectionStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 07:29:12 -0700110 *os << stats.ToJson();
hbosda389e32016-10-25 10:55:08 -0700111}
112
hbos09bc1282016-11-08 06:29:22 -0800113void PrintTo(const RTCMediaStreamStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 07:29:12 -0700114 *os << stats.ToJson();
hbos09bc1282016-11-08 06:29:22 -0800115}
116
117void PrintTo(const RTCMediaStreamTrackStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 07:29:12 -0700118 *os << stats.ToJson();
hbos09bc1282016-11-08 06:29:22 -0800119}
120
hboseeafe942016-11-01 03:00:17 -0700121void PrintTo(const RTCInboundRTPStreamStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 07:29:12 -0700122 *os << stats.ToJson();
hboseeafe942016-11-01 03:00:17 -0700123}
124
hbos6ded1902016-11-01 01:50:46 -0700125void PrintTo(const RTCOutboundRTPStreamStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 07:29:12 -0700126 *os << stats.ToJson();
hbos6ded1902016-11-01 01:50:46 -0700127}
128
Henrik Boström883eefc2019-05-27 13:40:25 +0200129void PrintTo(const RTCRemoteInboundRtpStreamStats& stats, ::std::ostream* os) {
130 *os << stats.ToJson();
131}
132
Henrik Boström646fda02019-05-22 15:49:42 +0200133void PrintTo(const RTCAudioSourceStats& stats, ::std::ostream* os) {
134 *os << stats.ToJson();
135}
136
137void PrintTo(const RTCVideoSourceStats& stats, ::std::ostream* os) {
138 *os << stats.ToJson();
139}
140
hbosda389e32016-10-25 10:55:08 -0700141void PrintTo(const RTCTransportStats& stats, ::std::ostream* os) {
ehmaldonado35a872c2017-07-28 07:29:12 -0700142 *os << stats.ToJson();
hbosda389e32016-10-25 10:55:08 -0700143}
144
hbosc82f2e12016-09-05 01:36:50 -0700145namespace {
146
147const int64_t kGetStatsReportTimeoutMs = 1000;
148
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +0100149// Fake data used by `SetupExampleStatsVoiceGraph()` to fill in remote outbound
150// stats.
151constexpr int64_t kRemoteOutboundStatsTimestampMs = 123;
152constexpr int64_t kRemoteOutboundStatsRemoteTimestampMs = 456;
153constexpr uint32_t kRemoteOutboundStatsPacketsSent = 7u;
154constexpr uint64_t kRemoteOutboundStatsBytesSent = 8u;
155constexpr uint64_t kRemoteOutboundStatsReportsCount = 9u;
156
hbos6ab97ce2016-10-03 14:16:56 -0700157struct CertificateInfo {
158 rtc::scoped_refptr<rtc::RTCCertificate> certificate;
159 std::vector<std::string> ders;
160 std::vector<std::string> pems;
161 std::vector<std::string> fingerprints;
162};
163
Harald Alvestranda3dab842018-01-14 09:18:58 +0100164// Return the ID for an object of the given type in a report.
165// The object must be present and be unique.
166template <typename T>
167std::string IdForType(const RTCStatsReport* report) {
168 auto stats_of_my_type = report->RTCStatsReport::GetStatsOfType<T>();
169 // We cannot use ASSERT here, since we're within a function.
Mirko Bonadeie12c1fe2018-07-03 12:53:23 +0200170 EXPECT_EQ(1U, stats_of_my_type.size())
Harald Alvestranda3dab842018-01-14 09:18:58 +0100171 << "Unexpected number of stats of this type";
172 if (stats_of_my_type.size() == 1) {
173 return stats_of_my_type[0]->id();
174 } else {
175 // Return something that is not going to be a valid stas ID.
176 return "Type not found";
177 }
178}
179
hbos6ab97ce2016-10-03 14:16:56 -0700180std::unique_ptr<CertificateInfo> CreateFakeCertificateAndInfoFromDers(
181 const std::vector<std::string>& ders) {
182 RTC_CHECK(!ders.empty());
183 std::unique_ptr<CertificateInfo> info(new CertificateInfo());
184 info->ders = ders;
185 for (const std::string& der : ders) {
186 info->pems.push_back(rtc::SSLIdentity::DerToPem(
Yves Gerey665174f2018-06-19 15:03:05 +0200187 "CERTIFICATE", reinterpret_cast<const unsigned char*>(der.c_str()),
hbos6ab97ce2016-10-03 14:16:56 -0700188 der.length()));
189 }
190 info->certificate =
191 rtc::RTCCertificate::Create(std::unique_ptr<rtc::FakeSSLIdentity>(
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800192 new rtc::FakeSSLIdentity(info->pems)));
hbos6ab97ce2016-10-03 14:16:56 -0700193 // Strip header/footer and newline characters of PEM strings.
194 for (size_t i = 0; i < info->pems.size(); ++i) {
Steve Anton1c9c9fc2019-02-14 15:13:09 -0800195 absl::StrReplaceAll({{"-----BEGIN CERTIFICATE-----", ""},
196 {"-----END CERTIFICATE-----", ""},
197 {"\n", ""}},
198 &info->pems[i]);
hbos6ab97ce2016-10-03 14:16:56 -0700199 }
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800200 // Fingerprints for the whole certificate chain, starting with leaf
201 // certificate.
Benjamin Wright6c6c9df2018-10-25 01:16:26 -0700202 const rtc::SSLCertChain& chain = info->certificate->GetSSLCertificateChain();
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800203 std::unique_ptr<rtc::SSLFingerprint> fp;
204 for (size_t i = 0; i < chain.GetSize(); i++) {
Steve Anton4905edb2018-10-15 19:27:44 -0700205 fp = rtc::SSLFingerprint::Create("sha-1", chain.Get(i));
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800206 EXPECT_TRUE(fp);
207 info->fingerprints.push_back(fp->GetRfc4572Fingerprint());
hbos6ab97ce2016-10-03 14:16:56 -0700208 }
209 EXPECT_EQ(info->ders.size(), info->fingerprints.size());
210 return info;
211}
212
hbosab9f6e42016-10-07 02:18:47 -0700213std::unique_ptr<cricket::Candidate> CreateFakeCandidate(
214 const std::string& hostname,
215 int port,
216 const std::string& protocol,
Gary Liu37e489c2017-11-21 10:49:36 -0800217 const rtc::AdapterType adapter_type,
hbosab9f6e42016-10-07 02:18:47 -0700218 const std::string& candidate_type,
Jonas Oreland0d13bbd2022-03-02 11:17:36 +0100219 uint32_t priority,
220 const rtc::AdapterType underlying_type_for_vpn =
221 rtc::ADAPTER_TYPE_UNKNOWN) {
hbosab9f6e42016-10-07 02:18:47 -0700222 std::unique_ptr<cricket::Candidate> candidate(new cricket::Candidate());
223 candidate->set_address(rtc::SocketAddress(hostname, port));
224 candidate->set_protocol(protocol);
Gary Liu37e489c2017-11-21 10:49:36 -0800225 candidate->set_network_type(adapter_type);
Jonas Oreland0d13bbd2022-03-02 11:17:36 +0100226 candidate->set_underlying_type_for_vpn(underlying_type_for_vpn);
hbosab9f6e42016-10-07 02:18:47 -0700227 candidate->set_type(candidate_type);
228 candidate->set_priority(priority);
229 return candidate;
230}
231
Taylor Brandstetter64851c02021-06-24 13:32:50 -0700232class FakeAudioProcessor : public AudioProcessorInterface {
233 public:
234 FakeAudioProcessor() {}
235 ~FakeAudioProcessor() {}
236
237 private:
238 AudioProcessorInterface::AudioProcessorStatistics GetStats(
239 bool has_recv_streams) override {
240 AudioProcessorStatistics stats;
241 stats.apm_statistics.echo_return_loss = 2.0;
242 stats.apm_statistics.echo_return_loss_enhancement = 3.0;
243 return stats;
244 }
245};
246
Yves Gerey665174f2018-06-19 15:03:05 +0200247class FakeAudioTrackForStats : public MediaStreamTrack<AudioTrackInterface> {
hbos09bc1282016-11-08 06:29:22 -0800248 public:
249 static rtc::scoped_refptr<FakeAudioTrackForStats> Create(
250 const std::string& id,
Taylor Brandstetter64851c02021-06-24 13:32:50 -0700251 MediaStreamTrackInterface::TrackState state,
252 bool create_fake_audio_processor) {
Niels Möller027c7932022-01-25 13:56:07 +0100253 auto audio_track_stats = rtc::make_ref_counted<FakeAudioTrackForStats>(id);
hbos09bc1282016-11-08 06:29:22 -0800254 audio_track_stats->set_state(state);
Taylor Brandstetter64851c02021-06-24 13:32:50 -0700255 if (create_fake_audio_processor) {
256 audio_track_stats->processor_ =
257 rtc::make_ref_counted<FakeAudioProcessor>();
258 }
hbos09bc1282016-11-08 06:29:22 -0800259 return audio_track_stats;
260 }
261
Steve Anton36b29d12017-10-30 09:57:42 -0700262 explicit FakeAudioTrackForStats(const std::string& id)
263 : MediaStreamTrack<AudioTrackInterface>(id) {}
hbos09bc1282016-11-08 06:29:22 -0800264
265 std::string kind() const override {
266 return MediaStreamTrackInterface::kAudioKind;
267 }
268 webrtc::AudioSourceInterface* GetSource() const override { return nullptr; }
269 void AddSink(webrtc::AudioTrackSinkInterface* sink) override {}
270 void RemoveSink(webrtc::AudioTrackSinkInterface* sink) override {}
hbos9e302742017-01-20 02:47:10 -0800271 bool GetSignalLevel(int* level) override { return false; }
hbos09bc1282016-11-08 06:29:22 -0800272 rtc::scoped_refptr<AudioProcessorInterface> GetAudioProcessor() override {
Taylor Brandstetter64851c02021-06-24 13:32:50 -0700273 return processor_;
hbos09bc1282016-11-08 06:29:22 -0800274 }
Taylor Brandstetter64851c02021-06-24 13:32:50 -0700275
276 private:
277 rtc::scoped_refptr<FakeAudioProcessor> processor_;
hbos09bc1282016-11-08 06:29:22 -0800278};
279
Henrik Boström646fda02019-05-22 15:49:42 +0200280class FakeVideoTrackSourceForStats : public VideoTrackSourceInterface {
281 public:
282 static rtc::scoped_refptr<FakeVideoTrackSourceForStats> Create(
283 int input_width,
284 int input_height) {
Niels Möller027c7932022-01-25 13:56:07 +0100285 return rtc::make_ref_counted<FakeVideoTrackSourceForStats>(input_width,
286 input_height);
Henrik Boström646fda02019-05-22 15:49:42 +0200287 }
288
289 FakeVideoTrackSourceForStats(int input_width, int input_height)
290 : input_width_(input_width), input_height_(input_height) {}
291 ~FakeVideoTrackSourceForStats() override {}
292
293 // VideoTrackSourceInterface
294 bool is_screencast() const override { return false; }
295 absl::optional<bool> needs_denoising() const override { return false; }
296 bool GetStats(VideoTrackSourceInterface::Stats* stats) override {
297 stats->input_width = input_width_;
298 stats->input_height = input_height_;
299 return true;
300 }
301 // MediaSourceInterface (part of VideoTrackSourceInterface)
302 MediaSourceInterface::SourceState state() const override {
303 return MediaSourceInterface::SourceState::kLive;
304 }
305 bool remote() const override { return false; }
306 // NotifierInterface (part of MediaSourceInterface)
307 void RegisterObserver(ObserverInterface* observer) override {}
308 void UnregisterObserver(ObserverInterface* observer) override {}
309 // rtc::VideoSourceInterface<VideoFrame> (part of VideoTrackSourceInterface)
310 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
311 const rtc::VideoSinkWants& wants) override {}
312 void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override {}
Markus Handell6efc14b2020-05-05 20:11:13 +0200313 bool SupportsEncodedOutput() const override { return false; }
314 void GenerateKeyFrame() override {}
315 void AddEncodedSink(
316 rtc::VideoSinkInterface<RecordableEncodedFrame>* sink) override {}
317 void RemoveEncodedSink(
318 rtc::VideoSinkInterface<RecordableEncodedFrame>* sink) override {}
Henrik Boström646fda02019-05-22 15:49:42 +0200319
320 private:
321 int input_width_;
322 int input_height_;
323};
324
Yves Gerey665174f2018-06-19 15:03:05 +0200325class FakeVideoTrackForStats : public MediaStreamTrack<VideoTrackInterface> {
hbos09bc1282016-11-08 06:29:22 -0800326 public:
327 static rtc::scoped_refptr<FakeVideoTrackForStats> Create(
328 const std::string& id,
Henrik Boström646fda02019-05-22 15:49:42 +0200329 MediaStreamTrackInterface::TrackState state,
330 rtc::scoped_refptr<VideoTrackSourceInterface> source) {
Niels Möller027c7932022-01-25 13:56:07 +0100331 auto video_track =
332 rtc::make_ref_counted<FakeVideoTrackForStats>(id, std::move(source));
hbos09bc1282016-11-08 06:29:22 -0800333 video_track->set_state(state);
334 return video_track;
335 }
336
Henrik Boström646fda02019-05-22 15:49:42 +0200337 FakeVideoTrackForStats(const std::string& id,
338 rtc::scoped_refptr<VideoTrackSourceInterface> source)
339 : MediaStreamTrack<VideoTrackInterface>(id), source_(source) {}
hbos09bc1282016-11-08 06:29:22 -0800340
341 std::string kind() const override {
342 return MediaStreamTrackInterface::kVideoKind;
343 }
perkj773be362017-07-31 23:22:01 -0700344
345 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
Mirko Bonadeic4dd7302019-02-25 09:12:02 +0100346 const rtc::VideoSinkWants& wants) override {}
347 void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override {}
perkj773be362017-07-31 23:22:01 -0700348
Henrik Boström646fda02019-05-22 15:49:42 +0200349 VideoTrackSourceInterface* GetSource() const override {
350 return source_.get();
351 }
352
353 private:
354 rtc::scoped_refptr<VideoTrackSourceInterface> source_;
hbos09bc1282016-11-08 06:29:22 -0800355};
356
hbos84abeb12017-01-16 06:16:44 -0800357rtc::scoped_refptr<MediaStreamTrackInterface> CreateFakeTrack(
358 cricket::MediaType media_type,
hbos9e302742017-01-20 02:47:10 -0800359 const std::string& track_id,
Taylor Brandstetter64851c02021-06-24 13:32:50 -0700360 MediaStreamTrackInterface::TrackState track_state,
361 bool create_fake_audio_processor = false) {
hbos84abeb12017-01-16 06:16:44 -0800362 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
Taylor Brandstetter64851c02021-06-24 13:32:50 -0700363 return FakeAudioTrackForStats::Create(track_id, track_state,
364 create_fake_audio_processor);
hbos84abeb12017-01-16 06:16:44 -0800365 } else {
366 RTC_DCHECK_EQ(media_type, cricket::MEDIA_TYPE_VIDEO);
Henrik Boström646fda02019-05-22 15:49:42 +0200367 return FakeVideoTrackForStats::Create(track_id, track_state, nullptr);
hbos84abeb12017-01-16 06:16:44 -0800368 }
369}
370
Steve Anton57858b32018-02-15 15:19:50 -0800371rtc::scoped_refptr<MockRtpSenderInternal> CreateMockSender(
Henrik Boström646fda02019-05-22 15:49:42 +0200372 cricket::MediaType media_type,
373 rtc::scoped_refptr<MediaStreamTrackInterface> track,
Harald Alvestrandc72af932018-01-11 17:18:19 +0100374 uint32_t ssrc,
Harald Alvestranda3dab842018-01-14 09:18:58 +0100375 int attachment_id,
376 std::vector<std::string> local_stream_ids) {
Henrik Boström646fda02019-05-22 15:49:42 +0200377 RTC_DCHECK(!track ||
378 (track->kind() == MediaStreamTrackInterface::kAudioKind &&
379 media_type == cricket::MEDIA_TYPE_AUDIO) ||
380 (track->kind() == MediaStreamTrackInterface::kVideoKind &&
381 media_type == cricket::MEDIA_TYPE_VIDEO));
Niels Möller027c7932022-01-25 13:56:07 +0100382 auto sender = rtc::make_ref_counted<MockRtpSenderInternal>();
hbos9e302742017-01-20 02:47:10 -0800383 EXPECT_CALL(*sender, track()).WillRepeatedly(Return(track));
384 EXPECT_CALL(*sender, ssrc()).WillRepeatedly(Return(ssrc));
Henrik Boström646fda02019-05-22 15:49:42 +0200385 EXPECT_CALL(*sender, media_type()).WillRepeatedly(Return(media_type));
Yves Gerey665174f2018-06-19 15:03:05 +0200386 EXPECT_CALL(*sender, GetParameters()).WillRepeatedly(Invoke([ssrc]() {
387 RtpParameters params;
388 params.encodings.push_back(RtpEncodingParameters());
389 params.encodings[0].ssrc = ssrc;
390 return params;
391 }));
Harald Alvestrandc72af932018-01-11 17:18:19 +0100392 EXPECT_CALL(*sender, AttachmentId()).WillRepeatedly(Return(attachment_id));
Harald Alvestranda3dab842018-01-14 09:18:58 +0100393 EXPECT_CALL(*sender, stream_ids()).WillRepeatedly(Return(local_stream_ids));
Alessio Bazzica049e6112021-03-18 12:55:11 +0100394 EXPECT_CALL(*sender, SetTransceiverAsStopped());
hbos9e302742017-01-20 02:47:10 -0800395 return sender;
396}
397
Steve Anton57858b32018-02-15 15:19:50 -0800398rtc::scoped_refptr<MockRtpReceiverInternal> CreateMockReceiver(
Mirko Bonadeic61ce0d2017-11-21 17:04:20 +0100399 const rtc::scoped_refptr<MediaStreamTrackInterface>& track,
Harald Alvestrandc72af932018-01-11 17:18:19 +0100400 uint32_t ssrc,
401 int attachment_id) {
Niels Möller027c7932022-01-25 13:56:07 +0100402 auto receiver = rtc::make_ref_counted<MockRtpReceiverInternal>();
hbos9e302742017-01-20 02:47:10 -0800403 EXPECT_CALL(*receiver, track()).WillRepeatedly(Return(track));
Harald Alvestranda3dab842018-01-14 09:18:58 +0100404 EXPECT_CALL(*receiver, streams())
405 .WillRepeatedly(
406 Return(std::vector<rtc::scoped_refptr<MediaStreamInterface>>({})));
407
Yves Gerey665174f2018-06-19 15:03:05 +0200408 EXPECT_CALL(*receiver, media_type())
409 .WillRepeatedly(
410 Return(track->kind() == MediaStreamTrackInterface::kAudioKind
411 ? cricket::MEDIA_TYPE_AUDIO
412 : cricket::MEDIA_TYPE_VIDEO));
413 EXPECT_CALL(*receiver, GetParameters()).WillRepeatedly(Invoke([ssrc]() {
414 RtpParameters params;
415 params.encodings.push_back(RtpEncodingParameters());
416 params.encodings[0].ssrc = ssrc;
417 return params;
418 }));
Harald Alvestrandc72af932018-01-11 17:18:19 +0100419 EXPECT_CALL(*receiver, AttachmentId()).WillRepeatedly(Return(attachment_id));
Tommi6589def2022-02-17 23:36:47 +0100420 EXPECT_CALL(*receiver, Stop()).WillRepeatedly(Return());
hbos9e302742017-01-20 02:47:10 -0800421 return receiver;
422}
423
Steve Anton5b387312018-02-02 16:00:20 -0800424class RTCStatsCollectorWrapper {
hbosd565b732016-08-30 14:04:35 -0700425 public:
Steve Anton5b387312018-02-02 16:00:20 -0800426 explicit RTCStatsCollectorWrapper(
427 rtc::scoped_refptr<FakePeerConnectionForStats> pc)
428 : pc_(pc),
429 stats_collector_(
Niels Möllerafb246b2022-04-20 14:26:50 +0200430 RTCStatsCollector::Create(pc.get(),
431 50 * rtc::kNumMicrosecsPerMillisec)) {}
hbosd565b732016-08-30 14:04:35 -0700432
Steve Anton5b387312018-02-02 16:00:20 -0800433 rtc::scoped_refptr<RTCStatsCollector> stats_collector() {
434 return stats_collector_;
hbosd565b732016-08-30 14:04:35 -0700435 }
436
Henrik Boström5b3541f2018-03-19 13:52:56 +0100437 rtc::scoped_refptr<const RTCStatsReport> GetStatsReport() {
438 rtc::scoped_refptr<RTCStatsObtainer> callback = RTCStatsObtainer::Create();
439 stats_collector_->GetStatsReport(callback);
440 return WaitForReport(callback);
441 }
442
443 rtc::scoped_refptr<const RTCStatsReport> GetStatsReportWithSenderSelector(
444 rtc::scoped_refptr<RtpSenderInternal> selector) {
445 rtc::scoped_refptr<RTCStatsObtainer> callback = RTCStatsObtainer::Create();
446 stats_collector_->GetStatsReport(selector, callback);
447 return WaitForReport(callback);
448 }
449
450 rtc::scoped_refptr<const RTCStatsReport> GetStatsReportWithReceiverSelector(
451 rtc::scoped_refptr<RtpReceiverInternal> selector) {
452 rtc::scoped_refptr<RTCStatsObtainer> callback = RTCStatsObtainer::Create();
453 stats_collector_->GetStatsReport(selector, callback);
454 return WaitForReport(callback);
455 }
456
Steve Anton5b387312018-02-02 16:00:20 -0800457 rtc::scoped_refptr<const RTCStatsReport> GetFreshStatsReport() {
458 stats_collector_->ClearCachedStatsReport();
459 return GetStatsReport();
460 }
461
Henrik Boström5b3541f2018-03-19 13:52:56 +0100462 rtc::scoped_refptr<MockRtpSenderInternal> SetupLocalTrackAndSender(
463 cricket::MediaType media_type,
464 const std::string& track_id,
465 uint32_t ssrc,
Henrik Boström646fda02019-05-22 15:49:42 +0200466 bool add_stream,
467 int attachment_id) {
Harald Alvestrand89061872018-01-02 14:08:34 +0100468 rtc::scoped_refptr<MediaStream> local_stream;
469 if (add_stream) {
Seth Hampson845e8782018-03-02 11:34:10 -0800470 local_stream = MediaStream::Create("LocalStreamId");
Steve Anton5b387312018-02-02 16:00:20 -0800471 pc_->mutable_local_streams()->AddStream(local_stream);
Harald Alvestrand89061872018-01-02 14:08:34 +0100472 }
hbos84abeb12017-01-16 06:16:44 -0800473
474 rtc::scoped_refptr<MediaStreamTrackInterface> track;
475 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
hbos9e302742017-01-20 02:47:10 -0800476 track = CreateFakeTrack(media_type, track_id,
477 MediaStreamTrackInterface::kLive);
Harald Alvestrand89061872018-01-02 14:08:34 +0100478 if (add_stream) {
Harald Alvestrand2f7ad282022-04-21 11:35:43 +0000479 local_stream->AddTrack(rtc::scoped_refptr<AudioTrackInterface>(
480 static_cast<AudioTrackInterface*>(track.get())));
Harald Alvestrand89061872018-01-02 14:08:34 +0100481 }
hbos84abeb12017-01-16 06:16:44 -0800482 } else {
hbos9e302742017-01-20 02:47:10 -0800483 track = CreateFakeTrack(media_type, track_id,
484 MediaStreamTrackInterface::kLive);
Harald Alvestrand89061872018-01-02 14:08:34 +0100485 if (add_stream) {
Harald Alvestrand2f7ad282022-04-21 11:35:43 +0000486 local_stream->AddTrack(rtc::scoped_refptr<VideoTrackInterface>(
487 static_cast<VideoTrackInterface*>(track.get())));
Harald Alvestrand89061872018-01-02 14:08:34 +0100488 }
hbos84abeb12017-01-16 06:16:44 -0800489 }
490
Steve Anton57858b32018-02-15 15:19:50 -0800491 rtc::scoped_refptr<MockRtpSenderInternal> sender =
Henrik Boström646fda02019-05-22 15:49:42 +0200492 CreateMockSender(media_type, track, ssrc, attachment_id, {});
Tommi6589def2022-02-17 23:36:47 +0100493 EXPECT_CALL(*sender, Stop());
494 EXPECT_CALL(*sender, SetMediaChannel(_));
Steve Anton5b387312018-02-02 16:00:20 -0800495 pc_->AddSender(sender);
Henrik Boström5b3541f2018-03-19 13:52:56 +0100496 return sender;
hbos84abeb12017-01-16 06:16:44 -0800497 }
498
Henrik Boström5b3541f2018-03-19 13:52:56 +0100499 rtc::scoped_refptr<MockRtpReceiverInternal> SetupRemoteTrackAndReceiver(
500 cricket::MediaType media_type,
501 const std::string& track_id,
502 const std::string& stream_id,
503 uint32_t ssrc) {
hbos84abeb12017-01-16 06:16:44 -0800504 rtc::scoped_refptr<MediaStream> remote_stream =
Henrik Boström5b3541f2018-03-19 13:52:56 +0100505 MediaStream::Create(stream_id);
Steve Anton5b387312018-02-02 16:00:20 -0800506 pc_->mutable_remote_streams()->AddStream(remote_stream);
hbos84abeb12017-01-16 06:16:44 -0800507
508 rtc::scoped_refptr<MediaStreamTrackInterface> track;
509 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
hbos9e302742017-01-20 02:47:10 -0800510 track = CreateFakeTrack(media_type, track_id,
511 MediaStreamTrackInterface::kLive);
Harald Alvestrand2f7ad282022-04-21 11:35:43 +0000512 remote_stream->AddTrack(rtc::scoped_refptr<AudioTrackInterface>(
513 static_cast<AudioTrackInterface*>(track.get())));
hbos84abeb12017-01-16 06:16:44 -0800514 } else {
hbos9e302742017-01-20 02:47:10 -0800515 track = CreateFakeTrack(media_type, track_id,
516 MediaStreamTrackInterface::kLive);
Harald Alvestrand2f7ad282022-04-21 11:35:43 +0000517 remote_stream->AddTrack(rtc::scoped_refptr<VideoTrackInterface>(
518 static_cast<VideoTrackInterface*>(track.get())));
hbos84abeb12017-01-16 06:16:44 -0800519 }
520
Steve Anton57858b32018-02-15 15:19:50 -0800521 rtc::scoped_refptr<MockRtpReceiverInternal> receiver =
Harald Alvestrandc72af932018-01-11 17:18:19 +0100522 CreateMockReceiver(track, ssrc, 62);
Harald Alvestranda3dab842018-01-14 09:18:58 +0100523 EXPECT_CALL(*receiver, streams())
524 .WillRepeatedly(
525 Return(std::vector<rtc::scoped_refptr<MediaStreamInterface>>(
526 {remote_stream})));
Tommi6589def2022-02-17 23:36:47 +0100527 EXPECT_CALL(*receiver, SetMediaChannel(_)).WillRepeatedly(Return());
Steve Anton5b387312018-02-02 16:00:20 -0800528 pc_->AddReceiver(receiver);
Henrik Boström5b3541f2018-03-19 13:52:56 +0100529 return receiver;
hbos84abeb12017-01-16 06:16:44 -0800530 }
531
hbos9e302742017-01-20 02:47:10 -0800532 // Attaches tracks to peer connections by configuring RTP senders and RTP
533 // receivers according to the tracks' pairings with
534 // |[Voice/Video][Sender/Receiver]Info| and their SSRCs. Local tracks can be
535 // associated with multiple |[Voice/Video]SenderInfo|s, remote tracks can only
536 // be associated with one |[Voice/Video]ReceiverInfo|.
Henrik Boström646fda02019-05-22 15:49:42 +0200537 // Senders get assigned attachment ID "ssrc + 10".
hbos9e302742017-01-20 02:47:10 -0800538 void CreateMockRtpSendersReceiversAndChannels(
Harald Alvestranda3dab842018-01-14 09:18:58 +0100539 std::initializer_list<
540 std::pair<MediaStreamTrackInterface*, cricket::VoiceSenderInfo>>
541 local_audio_track_info_pairs,
542 std::initializer_list<
543 std::pair<MediaStreamTrackInterface*, cricket::VoiceReceiverInfo>>
544 remote_audio_track_info_pairs,
545 std::initializer_list<
546 std::pair<MediaStreamTrackInterface*, cricket::VideoSenderInfo>>
547 local_video_track_info_pairs,
548 std::initializer_list<
549 std::pair<MediaStreamTrackInterface*, cricket::VideoReceiverInfo>>
550 remote_video_track_info_pairs,
551 std::vector<std::string> local_stream_ids,
552 std::vector<rtc::scoped_refptr<MediaStreamInterface>> remote_streams) {
Steve Anton5b387312018-02-02 16:00:20 -0800553 cricket::VoiceMediaInfo voice_media_info;
554 cricket::VideoMediaInfo video_media_info;
555
hbos9e302742017-01-20 02:47:10 -0800556 // Local audio tracks and voice sender infos
557 for (auto& pair : local_audio_track_info_pairs) {
558 MediaStreamTrackInterface* local_audio_track = pair.first;
559 const cricket::VoiceSenderInfo& voice_sender_info = pair.second;
560 RTC_DCHECK_EQ(local_audio_track->kind(),
561 MediaStreamTrackInterface::kAudioKind);
562
Steve Anton5b387312018-02-02 16:00:20 -0800563 voice_media_info.senders.push_back(voice_sender_info);
Steve Anton57858b32018-02-15 15:19:50 -0800564 rtc::scoped_refptr<MockRtpSenderInternal> rtp_sender = CreateMockSender(
Henrik Boström646fda02019-05-22 15:49:42 +0200565 cricket::MEDIA_TYPE_AUDIO,
Harald Alvestrandc72af932018-01-11 17:18:19 +0100566 rtc::scoped_refptr<MediaStreamTrackInterface>(local_audio_track),
Henrik Boström646fda02019-05-22 15:49:42 +0200567 voice_sender_info.local_stats[0].ssrc,
568 voice_sender_info.local_stats[0].ssrc + 10, local_stream_ids);
Tomas Gunnarsson16de2162022-01-26 10:21:57 +0100569 EXPECT_CALL(*rtp_sender, SetMediaChannel(_)).WillRepeatedly(Return());
Tommi6589def2022-02-17 23:36:47 +0100570 EXPECT_CALL(*rtp_sender, Stop());
Steve Anton5b387312018-02-02 16:00:20 -0800571 pc_->AddSender(rtp_sender);
hbos9e302742017-01-20 02:47:10 -0800572 }
Steve Anton5b387312018-02-02 16:00:20 -0800573
hbos9e302742017-01-20 02:47:10 -0800574 // Remote audio tracks and voice receiver infos
575 for (auto& pair : remote_audio_track_info_pairs) {
576 MediaStreamTrackInterface* remote_audio_track = pair.first;
577 const cricket::VoiceReceiverInfo& voice_receiver_info = pair.second;
578 RTC_DCHECK_EQ(remote_audio_track->kind(),
579 MediaStreamTrackInterface::kAudioKind);
580
Steve Anton5b387312018-02-02 16:00:20 -0800581 voice_media_info.receivers.push_back(voice_receiver_info);
Steve Anton57858b32018-02-15 15:19:50 -0800582 rtc::scoped_refptr<MockRtpReceiverInternal> rtp_receiver =
583 CreateMockReceiver(
584 rtc::scoped_refptr<MediaStreamTrackInterface>(remote_audio_track),
Henrik Boström646fda02019-05-22 15:49:42 +0200585 voice_receiver_info.local_stats[0].ssrc,
586 voice_receiver_info.local_stats[0].ssrc + 10);
Harald Alvestranda3dab842018-01-14 09:18:58 +0100587 EXPECT_CALL(*rtp_receiver, streams())
588 .WillRepeatedly(Return(remote_streams));
Tommi6589def2022-02-17 23:36:47 +0100589 EXPECT_CALL(*rtp_receiver, SetMediaChannel(_)).WillRepeatedly(Return());
Steve Anton5b387312018-02-02 16:00:20 -0800590 pc_->AddReceiver(rtp_receiver);
hbos9e302742017-01-20 02:47:10 -0800591 }
Steve Anton5b387312018-02-02 16:00:20 -0800592
hbos9e302742017-01-20 02:47:10 -0800593 // Local video tracks and video sender infos
594 for (auto& pair : local_video_track_info_pairs) {
595 MediaStreamTrackInterface* local_video_track = pair.first;
596 const cricket::VideoSenderInfo& video_sender_info = pair.second;
597 RTC_DCHECK_EQ(local_video_track->kind(),
598 MediaStreamTrackInterface::kVideoKind);
599
Steve Anton5b387312018-02-02 16:00:20 -0800600 video_media_info.senders.push_back(video_sender_info);
Henrik Boströma0ff50c2020-05-05 15:54:46 +0200601 video_media_info.aggregated_senders.push_back(video_sender_info);
Steve Anton57858b32018-02-15 15:19:50 -0800602 rtc::scoped_refptr<MockRtpSenderInternal> rtp_sender = CreateMockSender(
Henrik Boström646fda02019-05-22 15:49:42 +0200603 cricket::MEDIA_TYPE_VIDEO,
Harald Alvestrandc72af932018-01-11 17:18:19 +0100604 rtc::scoped_refptr<MediaStreamTrackInterface>(local_video_track),
Henrik Boström646fda02019-05-22 15:49:42 +0200605 video_sender_info.local_stats[0].ssrc,
606 video_sender_info.local_stats[0].ssrc + 10, local_stream_ids);
Tomas Gunnarsson16de2162022-01-26 10:21:57 +0100607 EXPECT_CALL(*rtp_sender, SetMediaChannel(_)).WillRepeatedly(Return());
Tommi6589def2022-02-17 23:36:47 +0100608 EXPECT_CALL(*rtp_sender, Stop());
Steve Anton5b387312018-02-02 16:00:20 -0800609 pc_->AddSender(rtp_sender);
hbos9e302742017-01-20 02:47:10 -0800610 }
Steve Anton5b387312018-02-02 16:00:20 -0800611
hbos9e302742017-01-20 02:47:10 -0800612 // Remote video tracks and video receiver infos
613 for (auto& pair : remote_video_track_info_pairs) {
614 MediaStreamTrackInterface* remote_video_track = pair.first;
615 const cricket::VideoReceiverInfo& video_receiver_info = pair.second;
616 RTC_DCHECK_EQ(remote_video_track->kind(),
617 MediaStreamTrackInterface::kVideoKind);
618
Steve Anton5b387312018-02-02 16:00:20 -0800619 video_media_info.receivers.push_back(video_receiver_info);
Steve Anton57858b32018-02-15 15:19:50 -0800620 rtc::scoped_refptr<MockRtpReceiverInternal> rtp_receiver =
621 CreateMockReceiver(
622 rtc::scoped_refptr<MediaStreamTrackInterface>(remote_video_track),
Henrik Boström646fda02019-05-22 15:49:42 +0200623 video_receiver_info.local_stats[0].ssrc,
624 video_receiver_info.local_stats[0].ssrc + 10);
Harald Alvestranda3dab842018-01-14 09:18:58 +0100625 EXPECT_CALL(*rtp_receiver, streams())
626 .WillRepeatedly(Return(remote_streams));
Tommi6589def2022-02-17 23:36:47 +0100627 EXPECT_CALL(*rtp_receiver, SetMediaChannel(_)).WillRepeatedly(Return());
Steve Anton5b387312018-02-02 16:00:20 -0800628 pc_->AddReceiver(rtp_receiver);
hbos9e302742017-01-20 02:47:10 -0800629 }
hbos9e302742017-01-20 02:47:10 -0800630
Tommi19015512022-02-02 11:49:35 +0100631 pc_->AddVoiceChannel("audio", "transport", voice_media_info);
632 pc_->AddVideoChannel("video", "transport", video_media_info);
hbos9e302742017-01-20 02:47:10 -0800633 }
634
hbosd565b732016-08-30 14:04:35 -0700635 private:
Henrik Boström5b3541f2018-03-19 13:52:56 +0100636 rtc::scoped_refptr<const RTCStatsReport> WaitForReport(
637 rtc::scoped_refptr<RTCStatsObtainer> callback) {
Niels Möllerafb246b2022-04-20 14:26:50 +0200638 EXPECT_TRUE_WAIT(callback->report() != nullptr, kGetStatsReportTimeoutMs);
Henrik Boström5b3541f2018-03-19 13:52:56 +0100639 int64_t after = rtc::TimeUTCMicros();
640 for (const RTCStats& stats : *callback->report()) {
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +0100641 if (stats.type() == RTCRemoteInboundRtpStreamStats::kType ||
642 stats.type() == RTCRemoteOutboundRtpStreamStats::kType) {
643 // Ignore remote timestamps.
644 continue;
645 }
Henrik Boström5b3541f2018-03-19 13:52:56 +0100646 EXPECT_LE(stats.timestamp_us(), after);
647 }
648 return callback->report();
649 }
650
Steve Anton5b387312018-02-02 16:00:20 -0800651 rtc::scoped_refptr<FakePeerConnectionForStats> pc_;
652 rtc::scoped_refptr<RTCStatsCollector> stats_collector_;
hbosd565b732016-08-30 14:04:35 -0700653};
654
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200655class RTCStatsCollectorTest : public ::testing::Test {
hbosc82f2e12016-09-05 01:36:50 -0700656 public:
657 RTCStatsCollectorTest()
Niels Möller027c7932022-01-25 13:56:07 +0100658 : pc_(rtc::make_ref_counted<FakePeerConnectionForStats>()),
Steve Anton5b387312018-02-02 16:00:20 -0800659 stats_(new RTCStatsCollectorWrapper(pc_)) {}
hbosc82f2e12016-09-05 01:36:50 -0700660
hbos6ab97ce2016-10-03 14:16:56 -0700661 void ExpectReportContainsCertificateInfo(
662 const rtc::scoped_refptr<const RTCStatsReport>& report,
hbos23368e12016-12-21 04:29:17 -0800663 const CertificateInfo& certinfo) {
664 for (size_t i = 0; i < certinfo.fingerprints.size(); ++i) {
665 RTCCertificateStats expected_certificate_stats(
Yves Gerey665174f2018-06-19 15:03:05 +0200666 "RTCCertificate_" + certinfo.fingerprints[i], report->timestamp_us());
hbos23368e12016-12-21 04:29:17 -0800667 expected_certificate_stats.fingerprint = certinfo.fingerprints[i];
668 expected_certificate_stats.fingerprint_algorithm = "sha-1";
669 expected_certificate_stats.base64_certificate = certinfo.pems[i];
670 if (i + 1 < certinfo.fingerprints.size()) {
671 expected_certificate_stats.issuer_certificate_id =
672 "RTCCertificate_" + certinfo.fingerprints[i + 1];
hbos6ab97ce2016-10-03 14:16:56 -0700673 }
hbos23368e12016-12-21 04:29:17 -0800674 ASSERT_TRUE(report->Get(expected_certificate_stats.id()));
675 EXPECT_EQ(expected_certificate_stats,
Yves Gerey665174f2018-06-19 15:03:05 +0200676 report->Get(expected_certificate_stats.id())
677 ->cast_to<RTCCertificateStats>());
hbos6ab97ce2016-10-03 14:16:56 -0700678 }
679 }
680
Henrik Boström5b3541f2018-03-19 13:52:56 +0100681 struct ExampleStatsGraph {
682 rtc::scoped_refptr<RtpSenderInternal> sender;
683 rtc::scoped_refptr<RtpReceiverInternal> receiver;
684
685 rtc::scoped_refptr<const RTCStatsReport> full_report;
686 std::string send_codec_id;
687 std::string recv_codec_id;
688 std::string outbound_rtp_id;
689 std::string inbound_rtp_id;
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +0100690 std::string remote_outbound_rtp_id;
Henrik Boström5b3541f2018-03-19 13:52:56 +0100691 std::string transport_id;
692 std::string sender_track_id;
693 std::string receiver_track_id;
694 std::string remote_stream_id;
695 std::string peer_connection_id;
Henrik Boström646fda02019-05-22 15:49:42 +0200696 std::string media_source_id;
Henrik Boström5b3541f2018-03-19 13:52:56 +0100697 };
698
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +0100699 // Sets up the example stats graph (see ASCII art below) for a video only
700 // call. The graph is used for testing the stats selection algorithm (see
701 // https://w3c.github.io/webrtc-pc/#dfn-stats-selection-algorithm).
Henrik Boström5b3541f2018-03-19 13:52:56 +0100702 // These tests test the integration of the stats traversal algorithm inside of
703 // RTCStatsCollector. See rtcstatstraveral_unittest.cc for more stats
704 // traversal tests.
705 ExampleStatsGraph SetupExampleStatsGraphForSelectorTests() {
706 ExampleStatsGraph graph;
707
708 // codec (send)
709 graph.send_codec_id = "RTCCodec_VideoMid_Outbound_1";
710 cricket::VideoMediaInfo video_media_info;
711 RtpCodecParameters send_codec;
712 send_codec.payload_type = 1;
713 send_codec.clock_rate = 0;
714 video_media_info.send_codecs.insert(
715 std::make_pair(send_codec.payload_type, send_codec));
716 // codec (recv)
717 graph.recv_codec_id = "RTCCodec_VideoMid_Inbound_2";
718 RtpCodecParameters recv_codec;
719 recv_codec.payload_type = 2;
720 recv_codec.clock_rate = 0;
721 video_media_info.receive_codecs.insert(
722 std::make_pair(recv_codec.payload_type, recv_codec));
723 // outbound-rtp
724 graph.outbound_rtp_id = "RTCOutboundRTPVideoStream_3";
725 video_media_info.senders.push_back(cricket::VideoSenderInfo());
726 video_media_info.senders[0].local_stats.push_back(
727 cricket::SsrcSenderInfo());
728 video_media_info.senders[0].local_stats[0].ssrc = 3;
729 video_media_info.senders[0].codec_payload_type = send_codec.payload_type;
Henrik Boströma0ff50c2020-05-05 15:54:46 +0200730 video_media_info.aggregated_senders.push_back(video_media_info.senders[0]);
Henrik Boström5b3541f2018-03-19 13:52:56 +0100731 // inbound-rtp
732 graph.inbound_rtp_id = "RTCInboundRTPVideoStream_4";
733 video_media_info.receivers.push_back(cricket::VideoReceiverInfo());
734 video_media_info.receivers[0].local_stats.push_back(
735 cricket::SsrcReceiverInfo());
736 video_media_info.receivers[0].local_stats[0].ssrc = 4;
737 video_media_info.receivers[0].codec_payload_type = recv_codec.payload_type;
738 // transport
739 graph.transport_id = "RTCTransport_TransportName_1";
Tommi19015512022-02-02 11:49:35 +0100740 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström5b3541f2018-03-19 13:52:56 +0100741 // track (sender)
742 graph.sender = stats_->SetupLocalTrackAndSender(
Henrik Boström646fda02019-05-22 15:49:42 +0200743 cricket::MEDIA_TYPE_VIDEO, "LocalVideoTrackID", 3, false, 50);
Henrik Boström5b3541f2018-03-19 13:52:56 +0100744 graph.sender_track_id = "RTCMediaStreamTrack_sender_" +
Jonas Olsson6b1985d2018-07-05 11:59:48 +0200745 rtc::ToString(graph.sender->AttachmentId());
Henrik Boström5b3541f2018-03-19 13:52:56 +0100746 // track (receiver) and stream (remote stream)
747 graph.receiver = stats_->SetupRemoteTrackAndReceiver(
748 cricket::MEDIA_TYPE_VIDEO, "RemoteVideoTrackID", "RemoteStreamId", 4);
749 graph.receiver_track_id = "RTCMediaStreamTrack_receiver_" +
Jonas Olsson6b1985d2018-07-05 11:59:48 +0200750 rtc::ToString(graph.receiver->AttachmentId());
Henrik Boström5b3541f2018-03-19 13:52:56 +0100751 graph.remote_stream_id = "RTCMediaStream_RemoteStreamId";
752 // peer-connection
753 graph.peer_connection_id = "RTCPeerConnection";
Henrik Boström646fda02019-05-22 15:49:42 +0200754 // media-source (kind: video)
755 graph.media_source_id =
756 "RTCVideoSource_" + rtc::ToString(graph.sender->AttachmentId());
Henrik Boström5b3541f2018-03-19 13:52:56 +0100757
758 // Expected stats graph:
759 //
Henrik Boström646fda02019-05-22 15:49:42 +0200760 // +--- track (sender) stream (remote stream) ---> track (receiver)
761 // | ^ ^
762 // | | |
763 // | +--------- outbound-rtp inbound-rtp ---------------+
764 // | | | | | |
765 // | | v v v v
766 // | | codec (send) transport codec (recv) peer-connection
767 // v v
768 // media-source
Henrik Boström5b3541f2018-03-19 13:52:56 +0100769
770 // Verify the stats graph is set up correctly.
771 graph.full_report = stats_->GetStatsReport();
Henrik Boström646fda02019-05-22 15:49:42 +0200772 EXPECT_EQ(graph.full_report->size(), 10u);
Henrik Boström5b3541f2018-03-19 13:52:56 +0100773 EXPECT_TRUE(graph.full_report->Get(graph.send_codec_id));
774 EXPECT_TRUE(graph.full_report->Get(graph.recv_codec_id));
775 EXPECT_TRUE(graph.full_report->Get(graph.outbound_rtp_id));
776 EXPECT_TRUE(graph.full_report->Get(graph.inbound_rtp_id));
777 EXPECT_TRUE(graph.full_report->Get(graph.transport_id));
778 EXPECT_TRUE(graph.full_report->Get(graph.sender_track_id));
779 EXPECT_TRUE(graph.full_report->Get(graph.receiver_track_id));
780 EXPECT_TRUE(graph.full_report->Get(graph.remote_stream_id));
781 EXPECT_TRUE(graph.full_report->Get(graph.peer_connection_id));
Henrik Boström646fda02019-05-22 15:49:42 +0200782 EXPECT_TRUE(graph.full_report->Get(graph.media_source_id));
783 const auto& sender_track = graph.full_report->Get(graph.sender_track_id)
784 ->cast_to<RTCMediaStreamTrackStats>();
785 EXPECT_EQ(*sender_track.media_source_id, graph.media_source_id);
Henrik Boström5b3541f2018-03-19 13:52:56 +0100786 const auto& outbound_rtp = graph.full_report->Get(graph.outbound_rtp_id)
787 ->cast_to<RTCOutboundRTPStreamStats>();
Henrik Boström646fda02019-05-22 15:49:42 +0200788 EXPECT_EQ(*outbound_rtp.media_source_id, graph.media_source_id);
Henrik Boström5b3541f2018-03-19 13:52:56 +0100789 EXPECT_EQ(*outbound_rtp.codec_id, graph.send_codec_id);
790 EXPECT_EQ(*outbound_rtp.track_id, graph.sender_track_id);
791 EXPECT_EQ(*outbound_rtp.transport_id, graph.transport_id);
792 const auto& inbound_rtp = graph.full_report->Get(graph.inbound_rtp_id)
793 ->cast_to<RTCInboundRTPStreamStats>();
794 EXPECT_EQ(*inbound_rtp.codec_id, graph.recv_codec_id);
795 EXPECT_EQ(*inbound_rtp.track_id, graph.receiver_track_id);
796 EXPECT_EQ(*inbound_rtp.transport_id, graph.transport_id);
797
798 return graph;
799 }
800
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +0100801 // Sets up an example stats graph (see ASCII art below) for an audio only call
802 // and checks that the expected stats are generated.
803 ExampleStatsGraph SetupExampleStatsVoiceGraph(
804 bool add_remote_outbound_stats) {
805 constexpr uint32_t kLocalSsrc = 3;
806 constexpr uint32_t kRemoteSsrc = 4;
807 ExampleStatsGraph graph;
808
809 // codec (send)
810 graph.send_codec_id = "RTCCodec_VoiceMid_Outbound_1";
811 cricket::VoiceMediaInfo media_info;
812 RtpCodecParameters send_codec;
813 send_codec.payload_type = 1;
814 send_codec.clock_rate = 0;
815 media_info.send_codecs.insert(
816 std::make_pair(send_codec.payload_type, send_codec));
817 // codec (recv)
818 graph.recv_codec_id = "RTCCodec_VoiceMid_Inbound_2";
819 RtpCodecParameters recv_codec;
820 recv_codec.payload_type = 2;
821 recv_codec.clock_rate = 0;
822 media_info.receive_codecs.insert(
823 std::make_pair(recv_codec.payload_type, recv_codec));
824 // outbound-rtp
825 graph.outbound_rtp_id = "RTCOutboundRTPAudioStream_3";
826 media_info.senders.push_back(cricket::VoiceSenderInfo());
827 media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
828 media_info.senders[0].local_stats[0].ssrc = kLocalSsrc;
829 media_info.senders[0].codec_payload_type = send_codec.payload_type;
830 // inbound-rtp
831 graph.inbound_rtp_id = "RTCInboundRTPAudioStream_4";
832 media_info.receivers.push_back(cricket::VoiceReceiverInfo());
833 media_info.receivers[0].local_stats.push_back(cricket::SsrcReceiverInfo());
834 media_info.receivers[0].local_stats[0].ssrc = kRemoteSsrc;
835 media_info.receivers[0].codec_payload_type = recv_codec.payload_type;
836 // remote-outbound-rtp
837 if (add_remote_outbound_stats) {
838 graph.remote_outbound_rtp_id = "RTCRemoteOutboundRTPAudioStream_4";
839 media_info.receivers[0].last_sender_report_timestamp_ms =
840 kRemoteOutboundStatsTimestampMs;
841 media_info.receivers[0].last_sender_report_remote_timestamp_ms =
842 kRemoteOutboundStatsRemoteTimestampMs;
843 media_info.receivers[0].sender_reports_packets_sent =
844 kRemoteOutboundStatsPacketsSent;
845 media_info.receivers[0].sender_reports_bytes_sent =
846 kRemoteOutboundStatsBytesSent;
847 media_info.receivers[0].sender_reports_reports_count =
848 kRemoteOutboundStatsReportsCount;
849 }
850
851 // transport
852 graph.transport_id = "RTCTransport_TransportName_1";
Tommi19015512022-02-02 11:49:35 +0100853 pc_->AddVoiceChannel("VoiceMid", "TransportName", media_info);
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +0100854 // track (sender)
855 graph.sender = stats_->SetupLocalTrackAndSender(
856 cricket::MEDIA_TYPE_AUDIO, "LocalAudioTrackID", kLocalSsrc, false, 50);
857 graph.sender_track_id = "RTCMediaStreamTrack_sender_" +
858 rtc::ToString(graph.sender->AttachmentId());
859 // track (receiver) and stream (remote stream)
860 graph.receiver = stats_->SetupRemoteTrackAndReceiver(
861 cricket::MEDIA_TYPE_AUDIO, "RemoteAudioTrackID", "RemoteStreamId",
862 kRemoteSsrc);
863 graph.receiver_track_id = "RTCMediaStreamTrack_receiver_" +
864 rtc::ToString(graph.receiver->AttachmentId());
865 graph.remote_stream_id = "RTCMediaStream_RemoteStreamId";
866 // peer-connection
867 graph.peer_connection_id = "RTCPeerConnection";
868 // media-source (kind: video)
869 graph.media_source_id =
870 "RTCAudioSource_" + rtc::ToString(graph.sender->AttachmentId());
871
872 // Expected stats graph:
873 //
874 // +--- track (sender) stream (remote stream) ---> track (receiver)
875 // | ^ ^
876 // | | |
877 // | +--------- outbound-rtp inbound-rtp ---------------+
878 // | | | | | |
879 // | | v v v v
880 // | | codec (send) transport codec (recv) peer-connection
881 // v v
882 // media-source
883
884 // Verify the stats graph is set up correctly.
885 graph.full_report = stats_->GetStatsReport();
886 EXPECT_EQ(graph.full_report->size(), add_remote_outbound_stats ? 11u : 10u);
887 EXPECT_TRUE(graph.full_report->Get(graph.send_codec_id));
888 EXPECT_TRUE(graph.full_report->Get(graph.recv_codec_id));
889 EXPECT_TRUE(graph.full_report->Get(graph.outbound_rtp_id));
890 EXPECT_TRUE(graph.full_report->Get(graph.inbound_rtp_id));
891 EXPECT_TRUE(graph.full_report->Get(graph.transport_id));
892 EXPECT_TRUE(graph.full_report->Get(graph.sender_track_id));
893 EXPECT_TRUE(graph.full_report->Get(graph.receiver_track_id));
894 EXPECT_TRUE(graph.full_report->Get(graph.remote_stream_id));
895 EXPECT_TRUE(graph.full_report->Get(graph.peer_connection_id));
896 EXPECT_TRUE(graph.full_report->Get(graph.media_source_id));
897 // `graph.remote_outbound_rtp_id` is omitted on purpose so that expectations
898 // can be added by the caller depending on what value it sets for the
899 // `add_remote_outbound_stats` argument.
900 const auto& sender_track = graph.full_report->Get(graph.sender_track_id)
901 ->cast_to<RTCMediaStreamTrackStats>();
902 EXPECT_EQ(*sender_track.media_source_id, graph.media_source_id);
903 const auto& outbound_rtp = graph.full_report->Get(graph.outbound_rtp_id)
904 ->cast_to<RTCOutboundRTPStreamStats>();
905 EXPECT_EQ(*outbound_rtp.media_source_id, graph.media_source_id);
906 EXPECT_EQ(*outbound_rtp.codec_id, graph.send_codec_id);
907 EXPECT_EQ(*outbound_rtp.track_id, graph.sender_track_id);
908 EXPECT_EQ(*outbound_rtp.transport_id, graph.transport_id);
909 const auto& inbound_rtp = graph.full_report->Get(graph.inbound_rtp_id)
910 ->cast_to<RTCInboundRTPStreamStats>();
911 EXPECT_EQ(*inbound_rtp.codec_id, graph.recv_codec_id);
912 EXPECT_EQ(*inbound_rtp.track_id, graph.receiver_track_id);
913 EXPECT_EQ(*inbound_rtp.transport_id, graph.transport_id);
914
915 return graph;
916 }
917
hbosc82f2e12016-09-05 01:36:50 -0700918 protected:
Steve Anton5b387312018-02-02 16:00:20 -0800919 rtc::ScopedFakeClock fake_clock_;
920 rtc::scoped_refptr<FakePeerConnectionForStats> pc_;
921 std::unique_ptr<RTCStatsCollectorWrapper> stats_;
hbosc82f2e12016-09-05 01:36:50 -0700922};
923
924TEST_F(RTCStatsCollectorTest, SingleCallback) {
925 rtc::scoped_refptr<const RTCStatsReport> result;
Steve Anton5b387312018-02-02 16:00:20 -0800926 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&result));
Niels Möllerafb246b2022-04-20 14:26:50 +0200927 EXPECT_TRUE_WAIT(result != nullptr, kGetStatsReportTimeoutMs);
hbosc82f2e12016-09-05 01:36:50 -0700928}
929
930TEST_F(RTCStatsCollectorTest, MultipleCallbacks) {
Steve Anton5b387312018-02-02 16:00:20 -0800931 rtc::scoped_refptr<const RTCStatsReport> a, b, c;
932 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&a));
933 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&b));
934 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&c));
Niels Möllerafb246b2022-04-20 14:26:50 +0200935 EXPECT_TRUE_WAIT(a != nullptr, kGetStatsReportTimeoutMs);
936 EXPECT_TRUE_WAIT(b != nullptr, kGetStatsReportTimeoutMs);
937 EXPECT_TRUE_WAIT(c != nullptr, kGetStatsReportTimeoutMs);
Steve Anton5b387312018-02-02 16:00:20 -0800938
hbosc82f2e12016-09-05 01:36:50 -0700939 EXPECT_EQ(a.get(), b.get());
940 EXPECT_EQ(b.get(), c.get());
941}
942
943TEST_F(RTCStatsCollectorTest, CachedStatsReports) {
Artem Titov880fa812021-07-30 22:30:23 +0200944 // Caching should ensure `a` and `b` are the same report.
Steve Anton5b387312018-02-02 16:00:20 -0800945 rtc::scoped_refptr<const RTCStatsReport> a = stats_->GetStatsReport();
946 rtc::scoped_refptr<const RTCStatsReport> b = stats_->GetStatsReport();
hbosd565b732016-08-30 14:04:35 -0700947 EXPECT_EQ(a.get(), b.get());
948 // Invalidate cache by clearing it.
Steve Anton5b387312018-02-02 16:00:20 -0800949 stats_->stats_collector()->ClearCachedStatsReport();
950 rtc::scoped_refptr<const RTCStatsReport> c = stats_->GetStatsReport();
hbosd565b732016-08-30 14:04:35 -0700951 EXPECT_NE(b.get(), c.get());
952 // Invalidate cache by advancing time.
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100953 fake_clock_.AdvanceTime(TimeDelta::Millis(51));
Steve Anton5b387312018-02-02 16:00:20 -0800954 rtc::scoped_refptr<const RTCStatsReport> d = stats_->GetStatsReport();
hbosd565b732016-08-30 14:04:35 -0700955 EXPECT_TRUE(d);
956 EXPECT_NE(c.get(), d.get());
957}
958
hbosc82f2e12016-09-05 01:36:50 -0700959TEST_F(RTCStatsCollectorTest, MultipleCallbacksWithInvalidatedCacheInBetween) {
Steve Anton5b387312018-02-02 16:00:20 -0800960 rtc::scoped_refptr<const RTCStatsReport> a, b, c;
961 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&a));
962 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&b));
hbosc82f2e12016-09-05 01:36:50 -0700963 // Cache is invalidated after 50 ms.
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100964 fake_clock_.AdvanceTime(TimeDelta::Millis(51));
Steve Anton5b387312018-02-02 16:00:20 -0800965 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&c));
Niels Möllerafb246b2022-04-20 14:26:50 +0200966 EXPECT_TRUE_WAIT(a != nullptr, kGetStatsReportTimeoutMs);
967 EXPECT_TRUE_WAIT(b != nullptr, kGetStatsReportTimeoutMs);
968 EXPECT_TRUE_WAIT(c != nullptr, kGetStatsReportTimeoutMs);
hbosc82f2e12016-09-05 01:36:50 -0700969 EXPECT_EQ(a.get(), b.get());
Artem Titov880fa812021-07-30 22:30:23 +0200970 // The act of doing `AdvanceTime` processes all messages. If this was not the
971 // case we might not require `c` to be fresher than `b`.
hbosc82f2e12016-09-05 01:36:50 -0700972 EXPECT_NE(c.get(), b.get());
973}
974
Harald Alvestrand910cdc22020-01-09 12:58:23 +0100975TEST_F(RTCStatsCollectorTest, ToJsonProducesParseableJson) {
976 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
977 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
978 std::string json_format = report->ToJson();
Mirko Bonadeie99f6872021-06-24 15:24:59 +0200979
980 Json::CharReaderBuilder builder;
Harald Alvestrand910cdc22020-01-09 12:58:23 +0100981 Json::Value json_value;
Mirko Bonadeie99f6872021-06-24 15:24:59 +0200982 std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
983 ASSERT_TRUE(reader->parse(json_format.c_str(),
984 json_format.c_str() + json_format.size(),
985 &json_value, nullptr));
986
Harald Alvestrand910cdc22020-01-09 12:58:23 +0100987 // A very brief sanity check on the result.
988 EXPECT_EQ(report->size(), json_value.size());
989}
990
hbos6ab97ce2016-10-03 14:16:56 -0700991TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsSingle) {
Steve Anton5b387312018-02-02 16:00:20 -0800992 const char kTransportName[] = "transport";
993
994 pc_->AddVoiceChannel("audio", kTransportName);
995
hbos6ab97ce2016-10-03 14:16:56 -0700996 std::unique_ptr<CertificateInfo> local_certinfo =
997 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 15:03:05 +0200998 std::vector<std::string>({"(local) single certificate"}));
Steve Anton5b387312018-02-02 16:00:20 -0800999 pc_->SetLocalCertificate(kTransportName, local_certinfo->certificate);
1000
hbos6ab97ce2016-10-03 14:16:56 -07001001 std::unique_ptr<CertificateInfo> remote_certinfo =
1002 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 15:03:05 +02001003 std::vector<std::string>({"(remote) single certificate"}));
Taylor Brandstetterc3928662018-02-23 13:04:51 -08001004 pc_->SetRemoteCertChain(
Benjamin Wright6c6c9df2018-10-25 01:16:26 -07001005 kTransportName,
1006 remote_certinfo->certificate->GetSSLCertificateChain().Clone());
hbos6ab97ce2016-10-03 14:16:56 -07001007
Steve Anton5b387312018-02-02 16:00:20 -08001008 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos6ab97ce2016-10-03 14:16:56 -07001009
hbos23368e12016-12-21 04:29:17 -08001010 ExpectReportContainsCertificateInfo(report, *local_certinfo);
1011 ExpectReportContainsCertificateInfo(report, *remote_certinfo);
hbos6ab97ce2016-10-03 14:16:56 -07001012}
1013
hbos0adb8282016-11-23 02:32:06 -08001014TEST_F(RTCStatsCollectorTest, CollectRTCCodecStats) {
hbos0adb8282016-11-23 02:32:06 -08001015 // Audio
1016 cricket::VoiceMediaInfo voice_media_info;
1017
1018 RtpCodecParameters inbound_audio_codec;
1019 inbound_audio_codec.payload_type = 1;
deadbeefe702b302017-02-04 12:09:01 -08001020 inbound_audio_codec.kind = cricket::MEDIA_TYPE_AUDIO;
1021 inbound_audio_codec.name = "opus";
Oskar Sundbomcbc71b22017-11-16 10:56:07 +01001022 inbound_audio_codec.clock_rate = 1337;
Johannes Kron72d69152020-02-10 14:05:55 +01001023 inbound_audio_codec.num_channels = 1;
1024 inbound_audio_codec.parameters = {{"minptime", "10"}, {"useinbandfec", "1"}};
hbos0adb8282016-11-23 02:32:06 -08001025 voice_media_info.receive_codecs.insert(
1026 std::make_pair(inbound_audio_codec.payload_type, inbound_audio_codec));
1027
1028 RtpCodecParameters outbound_audio_codec;
1029 outbound_audio_codec.payload_type = 2;
deadbeefe702b302017-02-04 12:09:01 -08001030 outbound_audio_codec.kind = cricket::MEDIA_TYPE_AUDIO;
1031 outbound_audio_codec.name = "isac";
Oskar Sundbomcbc71b22017-11-16 10:56:07 +01001032 outbound_audio_codec.clock_rate = 1338;
Johannes Kron72d69152020-02-10 14:05:55 +01001033 outbound_audio_codec.num_channels = 2;
hbos0adb8282016-11-23 02:32:06 -08001034 voice_media_info.send_codecs.insert(
1035 std::make_pair(outbound_audio_codec.payload_type, outbound_audio_codec));
1036
Tommi19015512022-02-02 11:49:35 +01001037 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
hbos0adb8282016-11-23 02:32:06 -08001038
1039 // Video
1040 cricket::VideoMediaInfo video_media_info;
1041
1042 RtpCodecParameters inbound_video_codec;
1043 inbound_video_codec.payload_type = 3;
deadbeefe702b302017-02-04 12:09:01 -08001044 inbound_video_codec.kind = cricket::MEDIA_TYPE_VIDEO;
1045 inbound_video_codec.name = "H264";
Oskar Sundbomcbc71b22017-11-16 10:56:07 +01001046 inbound_video_codec.clock_rate = 1339;
Johannes Kron72d69152020-02-10 14:05:55 +01001047 inbound_video_codec.parameters = {{"level-asymmetry-allowed", "1"},
1048 {"packetization-mode", "1"},
1049 {"profile-level-id", "42001f"}};
hbos0adb8282016-11-23 02:32:06 -08001050 video_media_info.receive_codecs.insert(
1051 std::make_pair(inbound_video_codec.payload_type, inbound_video_codec));
1052
1053 RtpCodecParameters outbound_video_codec;
1054 outbound_video_codec.payload_type = 4;
deadbeefe702b302017-02-04 12:09:01 -08001055 outbound_video_codec.kind = cricket::MEDIA_TYPE_VIDEO;
1056 outbound_video_codec.name = "VP8";
Oskar Sundbomcbc71b22017-11-16 10:56:07 +01001057 outbound_video_codec.clock_rate = 1340;
hbos0adb8282016-11-23 02:32:06 -08001058 video_media_info.send_codecs.insert(
1059 std::make_pair(outbound_video_codec.payload_type, outbound_video_codec));
1060
Tommi19015512022-02-02 11:49:35 +01001061 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
hbos0adb8282016-11-23 02:32:06 -08001062
Steve Anton5b387312018-02-02 16:00:20 -08001063 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos0adb8282016-11-23 02:32:06 -08001064
Steve Anton57858b32018-02-15 15:19:50 -08001065 RTCCodecStats expected_inbound_audio_codec("RTCCodec_AudioMid_Inbound_1",
1066 report->timestamp_us());
hbos0adb8282016-11-23 02:32:06 -08001067 expected_inbound_audio_codec.payload_type = 1;
hbos13f54b22017-02-28 06:56:04 -08001068 expected_inbound_audio_codec.mime_type = "audio/opus";
hbos0adb8282016-11-23 02:32:06 -08001069 expected_inbound_audio_codec.clock_rate = 1337;
Johannes Kron72d69152020-02-10 14:05:55 +01001070 expected_inbound_audio_codec.channels = 1;
1071 expected_inbound_audio_codec.sdp_fmtp_line = "minptime=10;useinbandfec=1";
Philipp Hancke95157a02020-11-16 20:08:27 +01001072 expected_inbound_audio_codec.transport_id = "RTCTransport_TransportName_1";
hbos0adb8282016-11-23 02:32:06 -08001073
Steve Anton57858b32018-02-15 15:19:50 -08001074 RTCCodecStats expected_outbound_audio_codec("RTCCodec_AudioMid_Outbound_2",
1075 report->timestamp_us());
hbos0adb8282016-11-23 02:32:06 -08001076 expected_outbound_audio_codec.payload_type = 2;
hbos13f54b22017-02-28 06:56:04 -08001077 expected_outbound_audio_codec.mime_type = "audio/isac";
hbos0adb8282016-11-23 02:32:06 -08001078 expected_outbound_audio_codec.clock_rate = 1338;
Johannes Kron72d69152020-02-10 14:05:55 +01001079 expected_outbound_audio_codec.channels = 2;
Philipp Hancke95157a02020-11-16 20:08:27 +01001080 expected_outbound_audio_codec.transport_id = "RTCTransport_TransportName_1";
hbos0adb8282016-11-23 02:32:06 -08001081
Steve Anton57858b32018-02-15 15:19:50 -08001082 RTCCodecStats expected_inbound_video_codec("RTCCodec_VideoMid_Inbound_3",
1083 report->timestamp_us());
hbos0adb8282016-11-23 02:32:06 -08001084 expected_inbound_video_codec.payload_type = 3;
hbos13f54b22017-02-28 06:56:04 -08001085 expected_inbound_video_codec.mime_type = "video/H264";
hbos0adb8282016-11-23 02:32:06 -08001086 expected_inbound_video_codec.clock_rate = 1339;
Johannes Kron72d69152020-02-10 14:05:55 +01001087 expected_inbound_video_codec.sdp_fmtp_line =
1088 "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f";
Philipp Hancke95157a02020-11-16 20:08:27 +01001089 expected_inbound_video_codec.transport_id = "RTCTransport_TransportName_1";
hbos0adb8282016-11-23 02:32:06 -08001090
Steve Anton57858b32018-02-15 15:19:50 -08001091 RTCCodecStats expected_outbound_video_codec("RTCCodec_VideoMid_Outbound_4",
1092 report->timestamp_us());
hbos0adb8282016-11-23 02:32:06 -08001093 expected_outbound_video_codec.payload_type = 4;
hbos13f54b22017-02-28 06:56:04 -08001094 expected_outbound_video_codec.mime_type = "video/VP8";
hbos0adb8282016-11-23 02:32:06 -08001095 expected_outbound_video_codec.clock_rate = 1340;
Philipp Hancke95157a02020-11-16 20:08:27 +01001096 expected_outbound_video_codec.transport_id = "RTCTransport_TransportName_1";
hbos0adb8282016-11-23 02:32:06 -08001097
nissec8ee8822017-01-18 07:20:55 -08001098 ASSERT_TRUE(report->Get(expected_inbound_audio_codec.id()));
Yves Gerey665174f2018-06-19 15:03:05 +02001099 EXPECT_EQ(
1100 expected_inbound_audio_codec,
1101 report->Get(expected_inbound_audio_codec.id())->cast_to<RTCCodecStats>());
hbos0adb8282016-11-23 02:32:06 -08001102
nissec8ee8822017-01-18 07:20:55 -08001103 ASSERT_TRUE(report->Get(expected_outbound_audio_codec.id()));
hbos0adb8282016-11-23 02:32:06 -08001104 EXPECT_EQ(expected_outbound_audio_codec,
Yves Gerey665174f2018-06-19 15:03:05 +02001105 report->Get(expected_outbound_audio_codec.id())
1106 ->cast_to<RTCCodecStats>());
hbos0adb8282016-11-23 02:32:06 -08001107
nissec8ee8822017-01-18 07:20:55 -08001108 ASSERT_TRUE(report->Get(expected_inbound_video_codec.id()));
Yves Gerey665174f2018-06-19 15:03:05 +02001109 EXPECT_EQ(
1110 expected_inbound_video_codec,
1111 report->Get(expected_inbound_video_codec.id())->cast_to<RTCCodecStats>());
hbos0adb8282016-11-23 02:32:06 -08001112
nissec8ee8822017-01-18 07:20:55 -08001113 ASSERT_TRUE(report->Get(expected_outbound_video_codec.id()));
hbos0adb8282016-11-23 02:32:06 -08001114 EXPECT_EQ(expected_outbound_video_codec,
Yves Gerey665174f2018-06-19 15:03:05 +02001115 report->Get(expected_outbound_video_codec.id())
1116 ->cast_to<RTCCodecStats>());
hbos0adb8282016-11-23 02:32:06 -08001117}
1118
hbos6ab97ce2016-10-03 14:16:56 -07001119TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsMultiple) {
Steve Anton5b387312018-02-02 16:00:20 -08001120 const char kAudioTransport[] = "audio";
1121 const char kVideoTransport[] = "video";
1122
1123 pc_->AddVoiceChannel("audio", kAudioTransport);
Tommi19015512022-02-02 11:49:35 +01001124
hbos6ab97ce2016-10-03 14:16:56 -07001125 std::unique_ptr<CertificateInfo> audio_local_certinfo =
1126 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 15:03:05 +02001127 std::vector<std::string>({"(local) audio"}));
Steve Anton5b387312018-02-02 16:00:20 -08001128 pc_->SetLocalCertificate(kAudioTransport, audio_local_certinfo->certificate);
hbos6ab97ce2016-10-03 14:16:56 -07001129 std::unique_ptr<CertificateInfo> audio_remote_certinfo =
1130 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 15:03:05 +02001131 std::vector<std::string>({"(remote) audio"}));
Taylor Brandstetterc3928662018-02-23 13:04:51 -08001132 pc_->SetRemoteCertChain(
1133 kAudioTransport,
Benjamin Wright6c6c9df2018-10-25 01:16:26 -07001134 audio_remote_certinfo->certificate->GetSSLCertificateChain().Clone());
hbos6ab97ce2016-10-03 14:16:56 -07001135
Steve Anton5b387312018-02-02 16:00:20 -08001136 pc_->AddVideoChannel("video", kVideoTransport);
hbos6ab97ce2016-10-03 14:16:56 -07001137 std::unique_ptr<CertificateInfo> video_local_certinfo =
1138 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 15:03:05 +02001139 std::vector<std::string>({"(local) video"}));
Steve Anton5b387312018-02-02 16:00:20 -08001140 pc_->SetLocalCertificate(kVideoTransport, video_local_certinfo->certificate);
hbos6ab97ce2016-10-03 14:16:56 -07001141 std::unique_ptr<CertificateInfo> video_remote_certinfo =
1142 CreateFakeCertificateAndInfoFromDers(
Yves Gerey665174f2018-06-19 15:03:05 +02001143 std::vector<std::string>({"(remote) video"}));
Taylor Brandstetterc3928662018-02-23 13:04:51 -08001144 pc_->SetRemoteCertChain(
1145 kVideoTransport,
Benjamin Wright6c6c9df2018-10-25 01:16:26 -07001146 video_remote_certinfo->certificate->GetSSLCertificateChain().Clone());
hbos6ab97ce2016-10-03 14:16:56 -07001147
Steve Anton5b387312018-02-02 16:00:20 -08001148 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos23368e12016-12-21 04:29:17 -08001149 ExpectReportContainsCertificateInfo(report, *audio_local_certinfo);
1150 ExpectReportContainsCertificateInfo(report, *audio_remote_certinfo);
1151 ExpectReportContainsCertificateInfo(report, *video_local_certinfo);
1152 ExpectReportContainsCertificateInfo(report, *video_remote_certinfo);
hbos6ab97ce2016-10-03 14:16:56 -07001153}
1154
1155TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsChain) {
Steve Anton5b387312018-02-02 16:00:20 -08001156 const char kTransportName[] = "transport";
1157
1158 pc_->AddVoiceChannel("audio", kTransportName);
1159
hbos6ab97ce2016-10-03 14:16:56 -07001160 std::unique_ptr<CertificateInfo> local_certinfo =
Steve Anton5b387312018-02-02 16:00:20 -08001161 CreateFakeCertificateAndInfoFromDers(
1162 {"(local) this", "(local) is", "(local) a", "(local) chain"});
1163 pc_->SetLocalCertificate(kTransportName, local_certinfo->certificate);
1164
hbos6ab97ce2016-10-03 14:16:56 -07001165 std::unique_ptr<CertificateInfo> remote_certinfo =
Steve Anton5b387312018-02-02 16:00:20 -08001166 CreateFakeCertificateAndInfoFromDers({"(remote) this", "(remote) is",
1167 "(remote) another",
1168 "(remote) chain"});
Taylor Brandstetterc3928662018-02-23 13:04:51 -08001169 pc_->SetRemoteCertChain(
Benjamin Wright6c6c9df2018-10-25 01:16:26 -07001170 kTransportName,
1171 remote_certinfo->certificate->GetSSLCertificateChain().Clone());
hbos6ab97ce2016-10-03 14:16:56 -07001172
Steve Anton5b387312018-02-02 16:00:20 -08001173 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos23368e12016-12-21 04:29:17 -08001174 ExpectReportContainsCertificateInfo(report, *local_certinfo);
1175 ExpectReportContainsCertificateInfo(report, *remote_certinfo);
hbos6ab97ce2016-10-03 14:16:56 -07001176}
1177
Harald Alvestrand928e7a32019-07-31 07:16:45 -04001178TEST_F(RTCStatsCollectorTest, CollectTwoRTCDataChannelStatsWithPendingId) {
Niels Möllere7cc8832022-01-04 15:20:03 +01001179 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
1180 /*id=*/-1, DataChannelInterface::kConnecting));
1181 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
1182 /*id=*/-1, DataChannelInterface::kConnecting));
Harald Alvestrand928e7a32019-07-31 07:16:45 -04001183
1184 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1185}
1186
hboscc555c52016-10-18 12:48:31 -07001187TEST_F(RTCStatsCollectorTest, CollectRTCDataChannelStats) {
Harald Alvestrand928e7a32019-07-31 07:16:45 -04001188 // Note: The test assumes data channel IDs are predictable.
1189 // This is not a safe assumption, but in order to make it work for
1190 // the test, we reset the ID allocator at test start.
Taylor Brandstetter3a034e12020-07-09 15:32:34 -07001191 SctpDataChannel::ResetInternalIdAllocatorForTesting(-1);
Niels Möllere7cc8832022-01-04 15:20:03 +01001192 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
Taylor Brandstetter3a034e12020-07-09 15:32:34 -07001193 0, "MockSctpDataChannel0", DataChannelInterface::kConnecting, "udp", 1, 2,
1194 3, 4));
hbosdbb64d82016-12-21 01:57:46 -08001195 RTCDataChannelStats expected_data_channel0("RTCDataChannel_0", 0);
Taylor Brandstetter3a034e12020-07-09 15:32:34 -07001196 expected_data_channel0.label = "MockSctpDataChannel0";
hbosdbb64d82016-12-21 01:57:46 -08001197 expected_data_channel0.protocol = "udp";
Harald Alvestrand10ef8472020-06-05 15:38:51 +02001198 expected_data_channel0.data_channel_identifier = 0;
hbosdbb64d82016-12-21 01:57:46 -08001199 expected_data_channel0.state = "connecting";
1200 expected_data_channel0.messages_sent = 1;
1201 expected_data_channel0.bytes_sent = 2;
1202 expected_data_channel0.messages_received = 3;
1203 expected_data_channel0.bytes_received = 4;
1204
Niels Möllere7cc8832022-01-04 15:20:03 +01001205 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
1206 1, "MockSctpDataChannel1", DataChannelInterface::kOpen, "tcp", 5, 6, 7,
1207 8));
hbosdbb64d82016-12-21 01:57:46 -08001208 RTCDataChannelStats expected_data_channel1("RTCDataChannel_1", 0);
Taylor Brandstetter3a034e12020-07-09 15:32:34 -07001209 expected_data_channel1.label = "MockSctpDataChannel1";
hbosdbb64d82016-12-21 01:57:46 -08001210 expected_data_channel1.protocol = "tcp";
Harald Alvestrand10ef8472020-06-05 15:38:51 +02001211 expected_data_channel1.data_channel_identifier = 1;
hbosdbb64d82016-12-21 01:57:46 -08001212 expected_data_channel1.state = "open";
1213 expected_data_channel1.messages_sent = 5;
1214 expected_data_channel1.bytes_sent = 6;
1215 expected_data_channel1.messages_received = 7;
1216 expected_data_channel1.bytes_received = 8;
1217
Niels Möllere7cc8832022-01-04 15:20:03 +01001218 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
Taylor Brandstetter3a034e12020-07-09 15:32:34 -07001219 2, "MockSctpDataChannel2", DataChannelInterface::kClosing, "udp", 9, 10,
1220 11, 12));
hbosdbb64d82016-12-21 01:57:46 -08001221 RTCDataChannelStats expected_data_channel2("RTCDataChannel_2", 0);
Taylor Brandstetter3a034e12020-07-09 15:32:34 -07001222 expected_data_channel2.label = "MockSctpDataChannel2";
hbosdbb64d82016-12-21 01:57:46 -08001223 expected_data_channel2.protocol = "udp";
Harald Alvestrand10ef8472020-06-05 15:38:51 +02001224 expected_data_channel2.data_channel_identifier = 2;
hbosdbb64d82016-12-21 01:57:46 -08001225 expected_data_channel2.state = "closing";
1226 expected_data_channel2.messages_sent = 9;
1227 expected_data_channel2.bytes_sent = 10;
1228 expected_data_channel2.messages_received = 11;
1229 expected_data_channel2.bytes_received = 12;
1230
Niels Möllere7cc8832022-01-04 15:20:03 +01001231 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
1232 3, "MockSctpDataChannel3", DataChannelInterface::kClosed, "tcp", 13, 14,
1233 15, 16));
hbosdbb64d82016-12-21 01:57:46 -08001234 RTCDataChannelStats expected_data_channel3("RTCDataChannel_3", 0);
Taylor Brandstetter3a034e12020-07-09 15:32:34 -07001235 expected_data_channel3.label = "MockSctpDataChannel3";
hbosdbb64d82016-12-21 01:57:46 -08001236 expected_data_channel3.protocol = "tcp";
Harald Alvestrand10ef8472020-06-05 15:38:51 +02001237 expected_data_channel3.data_channel_identifier = 3;
hbosdbb64d82016-12-21 01:57:46 -08001238 expected_data_channel3.state = "closed";
1239 expected_data_channel3.messages_sent = 13;
1240 expected_data_channel3.bytes_sent = 14;
1241 expected_data_channel3.messages_received = 15;
1242 expected_data_channel3.bytes_received = 16;
hboscc555c52016-10-18 12:48:31 -07001243
Steve Anton5b387312018-02-02 16:00:20 -08001244 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1245
hbosdbb64d82016-12-21 01:57:46 -08001246 ASSERT_TRUE(report->Get(expected_data_channel0.id()));
Yves Gerey665174f2018-06-19 15:03:05 +02001247 EXPECT_EQ(
1248 expected_data_channel0,
1249 report->Get(expected_data_channel0.id())->cast_to<RTCDataChannelStats>());
hbosdbb64d82016-12-21 01:57:46 -08001250 ASSERT_TRUE(report->Get(expected_data_channel1.id()));
Yves Gerey665174f2018-06-19 15:03:05 +02001251 EXPECT_EQ(
1252 expected_data_channel1,
1253 report->Get(expected_data_channel1.id())->cast_to<RTCDataChannelStats>());
hbosdbb64d82016-12-21 01:57:46 -08001254 ASSERT_TRUE(report->Get(expected_data_channel2.id()));
Yves Gerey665174f2018-06-19 15:03:05 +02001255 EXPECT_EQ(
1256 expected_data_channel2,
1257 report->Get(expected_data_channel2.id())->cast_to<RTCDataChannelStats>());
hbosdbb64d82016-12-21 01:57:46 -08001258 ASSERT_TRUE(report->Get(expected_data_channel3.id()));
Yves Gerey665174f2018-06-19 15:03:05 +02001259 EXPECT_EQ(
1260 expected_data_channel3,
1261 report->Get(expected_data_channel3.id())->cast_to<RTCDataChannelStats>());
hboscc555c52016-10-18 12:48:31 -07001262}
1263
hbosab9f6e42016-10-07 02:18:47 -07001264TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidateStats) {
1265 // Candidates in the first transport stats.
Jonas Oreland0d13bbd2022-03-02 11:17:36 +01001266 std::unique_ptr<cricket::Candidate> a_local_host = CreateFakeCandidate(
1267 "1.2.3.4", 5, "a_local_host's protocol", rtc::ADAPTER_TYPE_VPN,
1268 cricket::LOCAL_PORT_TYPE, 0, rtc::ADAPTER_TYPE_ETHERNET);
hbosc42ba322016-12-21 03:31:45 -08001269 RTCLocalIceCandidateStats expected_a_local_host(
1270 "RTCIceCandidate_" + a_local_host->id(), 0);
hbosb4e426e2017-01-02 09:59:31 -08001271 expected_a_local_host.transport_id = "RTCTransport_a_0";
Gary Liu37e489c2017-11-21 10:49:36 -08001272 expected_a_local_host.network_type = "vpn";
hbosc42ba322016-12-21 03:31:45 -08001273 expected_a_local_host.ip = "1.2.3.4";
Philipp Hanckea9ba4502021-03-22 13:22:54 +01001274 expected_a_local_host.address = "1.2.3.4";
hbosc42ba322016-12-21 03:31:45 -08001275 expected_a_local_host.port = 5;
1276 expected_a_local_host.protocol = "a_local_host's protocol";
1277 expected_a_local_host.candidate_type = "host";
1278 expected_a_local_host.priority = 0;
Jonas Oreland0d13bbd2022-03-02 11:17:36 +01001279 expected_a_local_host.vpn = true;
1280 expected_a_local_host.network_adapter_type = RTCNetworkAdapterType::kEthernet;
hbosc42ba322016-12-21 03:31:45 -08001281
hbosab9f6e42016-10-07 02:18:47 -07001282 std::unique_ptr<cricket::Candidate> a_remote_srflx = CreateFakeCandidate(
Gary Liu37e489c2017-11-21 10:49:36 -08001283 "6.7.8.9", 10, "remote_srflx's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
1284 cricket::STUN_PORT_TYPE, 1);
hbosc42ba322016-12-21 03:31:45 -08001285 RTCRemoteIceCandidateStats expected_a_remote_srflx(
1286 "RTCIceCandidate_" + a_remote_srflx->id(), 0);
hbosb4e426e2017-01-02 09:59:31 -08001287 expected_a_remote_srflx.transport_id = "RTCTransport_a_0";
hbosc42ba322016-12-21 03:31:45 -08001288 expected_a_remote_srflx.ip = "6.7.8.9";
Philipp Hanckea9ba4502021-03-22 13:22:54 +01001289 expected_a_remote_srflx.address = "6.7.8.9";
hbosc42ba322016-12-21 03:31:45 -08001290 expected_a_remote_srflx.port = 10;
1291 expected_a_remote_srflx.protocol = "remote_srflx's protocol";
1292 expected_a_remote_srflx.candidate_type = "srflx";
1293 expected_a_remote_srflx.priority = 1;
1294
hbosab9f6e42016-10-07 02:18:47 -07001295 std::unique_ptr<cricket::Candidate> a_local_prflx = CreateFakeCandidate(
Jonas Oreland0d13bbd2022-03-02 11:17:36 +01001296 "11.12.13.14", 15, "a_local_prflx's protocol",
1297 rtc::ADAPTER_TYPE_CELLULAR_2G, cricket::PRFLX_PORT_TYPE, 2);
hbosc42ba322016-12-21 03:31:45 -08001298 RTCLocalIceCandidateStats expected_a_local_prflx(
1299 "RTCIceCandidate_" + a_local_prflx->id(), 0);
hbosb4e426e2017-01-02 09:59:31 -08001300 expected_a_local_prflx.transport_id = "RTCTransport_a_0";
Gary Liu37e489c2017-11-21 10:49:36 -08001301 expected_a_local_prflx.network_type = "cellular";
hbosc42ba322016-12-21 03:31:45 -08001302 expected_a_local_prflx.ip = "11.12.13.14";
Philipp Hanckea9ba4502021-03-22 13:22:54 +01001303 expected_a_local_prflx.address = "11.12.13.14";
hbosc42ba322016-12-21 03:31:45 -08001304 expected_a_local_prflx.port = 15;
1305 expected_a_local_prflx.protocol = "a_local_prflx's protocol";
1306 expected_a_local_prflx.candidate_type = "prflx";
1307 expected_a_local_prflx.priority = 2;
Jonas Oreland0d13bbd2022-03-02 11:17:36 +01001308 expected_a_local_prflx.vpn = false;
1309 expected_a_local_prflx.network_adapter_type =
1310 RTCNetworkAdapterType::kCellular2g;
hbosc42ba322016-12-21 03:31:45 -08001311
hbosab9f6e42016-10-07 02:18:47 -07001312 std::unique_ptr<cricket::Candidate> a_remote_relay = CreateFakeCandidate(
Gary Liu37e489c2017-11-21 10:49:36 -08001313 "16.17.18.19", 20, "a_remote_relay's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
1314 cricket::RELAY_PORT_TYPE, 3);
hbosc42ba322016-12-21 03:31:45 -08001315 RTCRemoteIceCandidateStats expected_a_remote_relay(
1316 "RTCIceCandidate_" + a_remote_relay->id(), 0);
hbosb4e426e2017-01-02 09:59:31 -08001317 expected_a_remote_relay.transport_id = "RTCTransport_a_0";
hbosc42ba322016-12-21 03:31:45 -08001318 expected_a_remote_relay.ip = "16.17.18.19";
Philipp Hanckea9ba4502021-03-22 13:22:54 +01001319 expected_a_remote_relay.address = "16.17.18.19";
hbosc42ba322016-12-21 03:31:45 -08001320 expected_a_remote_relay.port = 20;
1321 expected_a_remote_relay.protocol = "a_remote_relay's protocol";
1322 expected_a_remote_relay.candidate_type = "relay";
1323 expected_a_remote_relay.priority = 3;
1324
Philipp Hancke95513752018-09-27 14:40:08 +02001325 std::unique_ptr<cricket::Candidate> a_local_relay = CreateFakeCandidate(
1326 "16.17.18.19", 21, "a_local_relay's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
1327 cricket::RELAY_PORT_TYPE, 1);
1328 a_local_relay->set_relay_protocol("tcp");
Philipp Hancke05b29c72022-02-02 12:06:15 +01001329 a_local_relay->set_url("turn:url1");
Philipp Hancke95513752018-09-27 14:40:08 +02001330
Philipp Hanckefbd52c02021-11-10 23:02:17 +01001331 RTCLocalIceCandidateStats expected_a_local_relay(
Philipp Hancke95513752018-09-27 14:40:08 +02001332 "RTCIceCandidate_" + a_local_relay->id(), 0);
1333 expected_a_local_relay.transport_id = "RTCTransport_a_0";
Philipp Hanckefbd52c02021-11-10 23:02:17 +01001334 expected_a_local_relay.network_type = "unknown";
Philipp Hancke95513752018-09-27 14:40:08 +02001335 expected_a_local_relay.ip = "16.17.18.19";
Philipp Hanckea9ba4502021-03-22 13:22:54 +01001336 expected_a_local_relay.address = "16.17.18.19";
Philipp Hancke95513752018-09-27 14:40:08 +02001337 expected_a_local_relay.port = 21;
1338 expected_a_local_relay.protocol = "a_local_relay's protocol";
1339 expected_a_local_relay.relay_protocol = "tcp";
1340 expected_a_local_relay.candidate_type = "relay";
1341 expected_a_local_relay.priority = 1;
Philipp Hancke05b29c72022-02-02 12:06:15 +01001342 expected_a_local_relay.url = "turn:url1";
Jonas Oreland0d13bbd2022-03-02 11:17:36 +01001343 expected_a_local_relay.vpn = false;
1344 expected_a_local_relay.network_adapter_type = RTCNetworkAdapterType::kUnknown;
Philipp Hancke95513752018-09-27 14:40:08 +02001345
Philipp Hancke21c4b1e2021-11-11 07:45:59 +01001346 std::unique_ptr<cricket::Candidate> a_local_relay_prflx = CreateFakeCandidate(
1347 "11.12.13.20", 22, "a_local_relay_prflx's protocol",
1348 rtc::ADAPTER_TYPE_UNKNOWN, cricket::PRFLX_PORT_TYPE, 1);
1349 a_local_relay_prflx->set_relay_protocol("udp");
1350
1351 RTCLocalIceCandidateStats expected_a_local_relay_prflx(
1352 "RTCIceCandidate_" + a_local_relay_prflx->id(), 0);
1353 expected_a_local_relay_prflx.transport_id = "RTCTransport_a_0";
1354 expected_a_local_relay_prflx.network_type = "unknown";
1355 expected_a_local_relay_prflx.ip = "11.12.13.20";
1356 expected_a_local_relay_prflx.address = "11.12.13.20";
1357 expected_a_local_relay_prflx.port = 22;
1358 expected_a_local_relay_prflx.protocol = "a_local_relay_prflx's protocol";
1359 expected_a_local_relay_prflx.relay_protocol = "udp";
1360 expected_a_local_relay_prflx.candidate_type = "prflx";
1361 expected_a_local_relay_prflx.priority = 1;
Jonas Oreland0d13bbd2022-03-02 11:17:36 +01001362 expected_a_local_relay_prflx.vpn = false;
1363 expected_a_local_relay_prflx.network_adapter_type =
1364 RTCNetworkAdapterType::kUnknown;
Philipp Hancke21c4b1e2021-11-11 07:45:59 +01001365
hbosab9f6e42016-10-07 02:18:47 -07001366 // Candidates in the second transport stats.
Gary Liu37e489c2017-11-21 10:49:36 -08001367 std::unique_ptr<cricket::Candidate> b_local =
1368 CreateFakeCandidate("42.42.42.42", 42, "b_local's protocol",
1369 rtc::ADAPTER_TYPE_WIFI, cricket::LOCAL_PORT_TYPE, 42);
Yves Gerey665174f2018-06-19 15:03:05 +02001370 RTCLocalIceCandidateStats expected_b_local("RTCIceCandidate_" + b_local->id(),
1371 0);
hbosb4e426e2017-01-02 09:59:31 -08001372 expected_b_local.transport_id = "RTCTransport_b_0";
Gary Liu37e489c2017-11-21 10:49:36 -08001373 expected_b_local.network_type = "wifi";
hbosc42ba322016-12-21 03:31:45 -08001374 expected_b_local.ip = "42.42.42.42";
Philipp Hanckea9ba4502021-03-22 13:22:54 +01001375 expected_b_local.address = "42.42.42.42";
hbosc42ba322016-12-21 03:31:45 -08001376 expected_b_local.port = 42;
1377 expected_b_local.protocol = "b_local's protocol";
1378 expected_b_local.candidate_type = "host";
1379 expected_b_local.priority = 42;
Jonas Oreland0d13bbd2022-03-02 11:17:36 +01001380 expected_b_local.vpn = false;
1381 expected_b_local.network_adapter_type = RTCNetworkAdapterType::kWifi;
hbosc42ba322016-12-21 03:31:45 -08001382
hbosab9f6e42016-10-07 02:18:47 -07001383 std::unique_ptr<cricket::Candidate> b_remote = CreateFakeCandidate(
Gary Liu37e489c2017-11-21 10:49:36 -08001384 "42.42.42.42", 42, "b_remote's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
1385 cricket::LOCAL_PORT_TYPE, 42);
hbosc42ba322016-12-21 03:31:45 -08001386 RTCRemoteIceCandidateStats expected_b_remote(
1387 "RTCIceCandidate_" + b_remote->id(), 0);
hbosb4e426e2017-01-02 09:59:31 -08001388 expected_b_remote.transport_id = "RTCTransport_b_0";
hbosc42ba322016-12-21 03:31:45 -08001389 expected_b_remote.ip = "42.42.42.42";
Philipp Hanckea9ba4502021-03-22 13:22:54 +01001390 expected_b_remote.address = "42.42.42.42";
hbosc42ba322016-12-21 03:31:45 -08001391 expected_b_remote.port = 42;
1392 expected_b_remote.protocol = "b_remote's protocol";
1393 expected_b_remote.candidate_type = "host";
1394 expected_b_remote.priority = 42;
hbosab9f6e42016-10-07 02:18:47 -07001395
Philipp Hancke95513752018-09-27 14:40:08 +02001396 // Add candidate pairs to connection.
hbosab9f6e42016-10-07 02:18:47 -07001397 cricket::TransportChannelStats a_transport_channel_stats;
Jonas Oreland149dc722019-08-28 08:10:27 +02001398 a_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
hbosab9f6e42016-10-07 02:18:47 -07001399 cricket::ConnectionInfo());
Jonas Oreland149dc722019-08-28 08:10:27 +02001400 a_transport_channel_stats.ice_transport_stats.connection_infos[0]
1401 .local_candidate = *a_local_host.get();
1402 a_transport_channel_stats.ice_transport_stats.connection_infos[0]
1403 .remote_candidate = *a_remote_srflx.get();
1404 a_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
hbosab9f6e42016-10-07 02:18:47 -07001405 cricket::ConnectionInfo());
Jonas Oreland149dc722019-08-28 08:10:27 +02001406 a_transport_channel_stats.ice_transport_stats.connection_infos[1]
1407 .local_candidate = *a_local_prflx.get();
1408 a_transport_channel_stats.ice_transport_stats.connection_infos[1]
1409 .remote_candidate = *a_remote_relay.get();
1410 a_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
Philipp Hancke95513752018-09-27 14:40:08 +02001411 cricket::ConnectionInfo());
Jonas Oreland149dc722019-08-28 08:10:27 +02001412 a_transport_channel_stats.ice_transport_stats.connection_infos[2]
1413 .local_candidate = *a_local_relay.get();
1414 a_transport_channel_stats.ice_transport_stats.connection_infos[2]
1415 .remote_candidate = *a_remote_relay.get();
Philipp Hancke21c4b1e2021-11-11 07:45:59 +01001416 a_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
1417 cricket::ConnectionInfo());
1418 a_transport_channel_stats.ice_transport_stats.connection_infos[3]
1419 .local_candidate = *a_local_relay_prflx.get();
1420 a_transport_channel_stats.ice_transport_stats.connection_infos[3]
1421 .remote_candidate = *a_remote_relay.get();
Steve Anton5b387312018-02-02 16:00:20 -08001422
1423 pc_->AddVoiceChannel("audio", "a");
1424 pc_->SetTransportStats("a", a_transport_channel_stats);
hbosab9f6e42016-10-07 02:18:47 -07001425
1426 cricket::TransportChannelStats b_transport_channel_stats;
Jonas Oreland149dc722019-08-28 08:10:27 +02001427 b_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
hbosab9f6e42016-10-07 02:18:47 -07001428 cricket::ConnectionInfo());
Jonas Oreland149dc722019-08-28 08:10:27 +02001429 b_transport_channel_stats.ice_transport_stats.connection_infos[0]
1430 .local_candidate = *b_local.get();
1431 b_transport_channel_stats.ice_transport_stats.connection_infos[0]
1432 .remote_candidate = *b_remote.get();
hbosab9f6e42016-10-07 02:18:47 -07001433
Steve Anton5b387312018-02-02 16:00:20 -08001434 pc_->AddVideoChannel("video", "b");
1435 pc_->SetTransportStats("b", b_transport_channel_stats);
hbosab9f6e42016-10-07 02:18:47 -07001436
Steve Anton5b387312018-02-02 16:00:20 -08001437 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbosc42ba322016-12-21 03:31:45 -08001438
hbosb4e426e2017-01-02 09:59:31 -08001439 ASSERT_TRUE(report->Get(expected_a_local_host.id()));
Yves Gerey665174f2018-06-19 15:03:05 +02001440 EXPECT_EQ(expected_a_local_host, report->Get(expected_a_local_host.id())
1441 ->cast_to<RTCLocalIceCandidateStats>());
hbosb4e426e2017-01-02 09:59:31 -08001442 ASSERT_TRUE(report->Get(expected_a_remote_srflx.id()));
hbosc42ba322016-12-21 03:31:45 -08001443 EXPECT_EQ(expected_a_remote_srflx,
Yves Gerey665174f2018-06-19 15:03:05 +02001444 report->Get(expected_a_remote_srflx.id())
1445 ->cast_to<RTCRemoteIceCandidateStats>());
hbosb4e426e2017-01-02 09:59:31 -08001446 ASSERT_TRUE(report->Get(expected_a_local_prflx.id()));
Yves Gerey665174f2018-06-19 15:03:05 +02001447 EXPECT_EQ(expected_a_local_prflx, report->Get(expected_a_local_prflx.id())
1448 ->cast_to<RTCLocalIceCandidateStats>());
hbosb4e426e2017-01-02 09:59:31 -08001449 ASSERT_TRUE(report->Get(expected_a_remote_relay.id()));
hbosc42ba322016-12-21 03:31:45 -08001450 EXPECT_EQ(expected_a_remote_relay,
Yves Gerey665174f2018-06-19 15:03:05 +02001451 report->Get(expected_a_remote_relay.id())
1452 ->cast_to<RTCRemoteIceCandidateStats>());
Philipp Hanckefbd52c02021-11-10 23:02:17 +01001453 ASSERT_TRUE(report->Get(expected_a_local_relay.id()));
1454 EXPECT_EQ(expected_a_local_relay, report->Get(expected_a_local_relay.id())
1455 ->cast_to<RTCLocalIceCandidateStats>());
Philipp Hancke21c4b1e2021-11-11 07:45:59 +01001456 ASSERT_TRUE(report->Get(expected_a_local_relay_prflx.id()));
1457 EXPECT_EQ(expected_a_local_relay_prflx,
1458 report->Get(expected_a_local_relay_prflx.id())
1459 ->cast_to<RTCLocalIceCandidateStats>());
hbosb4e426e2017-01-02 09:59:31 -08001460 ASSERT_TRUE(report->Get(expected_b_local.id()));
Yves Gerey665174f2018-06-19 15:03:05 +02001461 EXPECT_EQ(
1462 expected_b_local,
1463 report->Get(expected_b_local.id())->cast_to<RTCLocalIceCandidateStats>());
hbosb4e426e2017-01-02 09:59:31 -08001464 ASSERT_TRUE(report->Get(expected_b_remote.id()));
Yves Gerey665174f2018-06-19 15:03:05 +02001465 EXPECT_EQ(expected_b_remote, report->Get(expected_b_remote.id())
1466 ->cast_to<RTCRemoteIceCandidateStats>());
hbosb4e426e2017-01-02 09:59:31 -08001467 EXPECT_TRUE(report->Get("RTCTransport_a_0"));
1468 EXPECT_TRUE(report->Get("RTCTransport_b_0"));
hbosab9f6e42016-10-07 02:18:47 -07001469}
1470
hbosc47a0c32016-10-11 14:54:49 -07001471TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidatePairStats) {
Steve Anton5b387312018-02-02 16:00:20 -08001472 const char kTransportName[] = "transport";
hbos338f78a2017-02-07 06:41:21 -08001473
Gary Liu37e489c2017-11-21 10:49:36 -08001474 std::unique_ptr<cricket::Candidate> local_candidate =
1475 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
1476 cricket::LOCAL_PORT_TYPE, 42);
hbosc47a0c32016-10-11 14:54:49 -07001477 std::unique_ptr<cricket::Candidate> remote_candidate = CreateFakeCandidate(
Gary Liu37e489c2017-11-21 10:49:36 -08001478 "42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_UNKNOWN,
1479 cricket::LOCAL_PORT_TYPE, 42);
hbosc47a0c32016-10-11 14:54:49 -07001480
hbosc47a0c32016-10-11 14:54:49 -07001481 cricket::ConnectionInfo connection_info;
hbos338f78a2017-02-07 06:41:21 -08001482 connection_info.best_connection = false;
hbosc47a0c32016-10-11 14:54:49 -07001483 connection_info.local_candidate = *local_candidate.get();
1484 connection_info.remote_candidate = *remote_candidate.get();
1485 connection_info.writable = true;
Taylor Brandstetter79326ea2021-09-28 15:09:53 -07001486 connection_info.sent_discarded_packets = 3;
1487 connection_info.sent_total_packets = 10;
1488 connection_info.packets_received = 51;
1489 connection_info.sent_discarded_bytes = 7;
hbosc47a0c32016-10-11 14:54:49 -07001490 connection_info.sent_total_bytes = 42;
1491 connection_info.recv_total_bytes = 1234;
hbosbf8d3e52017-02-28 06:34:47 -08001492 connection_info.total_round_trip_time_ms = 0;
Danil Chapovalov66cadcc2018-06-19 16:47:43 +02001493 connection_info.current_round_trip_time_ms = absl::nullopt;
hbosd82f5122016-12-09 04:12:39 -08001494 connection_info.recv_ping_requests = 2020;
hbose448dd52016-12-12 01:22:53 -08001495 connection_info.sent_ping_requests_total = 2020;
1496 connection_info.sent_ping_requests_before_first_response = 2000;
hbosc47a0c32016-10-11 14:54:49 -07001497 connection_info.recv_ping_responses = 4321;
1498 connection_info.sent_ping_responses = 1000;
hbos06495bc2017-01-02 08:08:18 -08001499 connection_info.state = cricket::IceCandidatePairState::IN_PROGRESS;
1500 connection_info.priority = 5555;
hbos92eaec62017-02-27 01:38:08 -08001501 connection_info.nominated = false;
hbosc47a0c32016-10-11 14:54:49 -07001502
1503 cricket::TransportChannelStats transport_channel_stats;
hbos0583b282016-11-30 01:50:14 -08001504 transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
Jonas Oreland149dc722019-08-28 08:10:27 +02001505 transport_channel_stats.ice_transport_stats.connection_infos.push_back(
1506 connection_info);
hbosc47a0c32016-10-11 14:54:49 -07001507
Steve Anton5b387312018-02-02 16:00:20 -08001508 pc_->AddVideoChannel("video", kTransportName);
1509 pc_->SetTransportStats(kTransportName, transport_channel_stats);
hbosc47a0c32016-10-11 14:54:49 -07001510
Steve Anton5b387312018-02-02 16:00:20 -08001511 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos0583b282016-11-30 01:50:14 -08001512
1513 RTCIceCandidatePairStats expected_pair("RTCIceCandidatePair_" +
1514 local_candidate->id() + "_" +
1515 remote_candidate->id(),
1516 report->timestamp_us());
1517 expected_pair.transport_id =
1518 "RTCTransport_transport_" +
Jonas Olsson6b1985d2018-07-05 11:59:48 +02001519 rtc::ToString(cricket::ICE_CANDIDATE_COMPONENT_RTP);
hbos0583b282016-11-30 01:50:14 -08001520 expected_pair.local_candidate_id = "RTCIceCandidate_" + local_candidate->id();
1521 expected_pair.remote_candidate_id =
1522 "RTCIceCandidate_" + remote_candidate->id();
hbos06495bc2017-01-02 08:08:18 -08001523 expected_pair.state = RTCStatsIceCandidatePairState::kInProgress;
1524 expected_pair.priority = 5555;
hbos92eaec62017-02-27 01:38:08 -08001525 expected_pair.nominated = false;
hbos0583b282016-11-30 01:50:14 -08001526 expected_pair.writable = true;
Taylor Brandstetter79326ea2021-09-28 15:09:53 -07001527 expected_pair.packets_sent = 7;
1528 expected_pair.packets_received = 51;
1529 expected_pair.packets_discarded_on_send = 3;
hbos0583b282016-11-30 01:50:14 -08001530 expected_pair.bytes_sent = 42;
1531 expected_pair.bytes_received = 1234;
Taylor Brandstetter79326ea2021-09-28 15:09:53 -07001532 expected_pair.bytes_discarded_on_send = 7;
hbosbf8d3e52017-02-28 06:34:47 -08001533 expected_pair.total_round_trip_time = 0.0;
hbosd82f5122016-12-09 04:12:39 -08001534 expected_pair.requests_received = 2020;
hbose448dd52016-12-12 01:22:53 -08001535 expected_pair.requests_sent = 2000;
hbos0583b282016-11-30 01:50:14 -08001536 expected_pair.responses_received = 4321;
1537 expected_pair.responses_sent = 1000;
hbose448dd52016-12-12 01:22:53 -08001538 expected_pair.consent_requests_sent = (2020 - 2000);
Artem Titovcfea2182021-08-10 01:22:31 +02001539 // `expected_pair.current_round_trip_time` should be undefined because the
hbosbf8d3e52017-02-28 06:34:47 -08001540 // current RTT is not set.
Artem Titovcfea2182021-08-10 01:22:31 +02001541 // `expected_pair.available_[outgoing/incoming]_bitrate` should be undefined
hbos338f78a2017-02-07 06:41:21 -08001542 // because is is not the current pair.
hbos0583b282016-11-30 01:50:14 -08001543
hbosdbb64d82016-12-21 01:57:46 -08001544 ASSERT_TRUE(report->Get(expected_pair.id()));
hbos0583b282016-11-30 01:50:14 -08001545 EXPECT_EQ(
1546 expected_pair,
1547 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
hbosb4e426e2017-01-02 09:59:31 -08001548 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
hbos0583b282016-11-30 01:50:14 -08001549
hbos92eaec62017-02-27 01:38:08 -08001550 // Set nominated and "GetStats" again.
Jonas Oreland149dc722019-08-28 08:10:27 +02001551 transport_channel_stats.ice_transport_stats.connection_infos[0].nominated =
1552 true;
Steve Anton5b387312018-02-02 16:00:20 -08001553 pc_->SetTransportStats(kTransportName, transport_channel_stats);
1554 report = stats_->GetFreshStatsReport();
hbos92eaec62017-02-27 01:38:08 -08001555 expected_pair.nominated = true;
1556 ASSERT_TRUE(report->Get(expected_pair.id()));
1557 EXPECT_EQ(
1558 expected_pair,
1559 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
1560 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
1561
hbosbf8d3e52017-02-28 06:34:47 -08001562 // Set round trip times and "GetStats" again.
Jonas Oreland149dc722019-08-28 08:10:27 +02001563 transport_channel_stats.ice_transport_stats.connection_infos[0]
1564 .total_round_trip_time_ms = 7331;
1565 transport_channel_stats.ice_transport_stats.connection_infos[0]
1566 .current_round_trip_time_ms = 1337;
Steve Anton5b387312018-02-02 16:00:20 -08001567 pc_->SetTransportStats(kTransportName, transport_channel_stats);
1568 report = stats_->GetFreshStatsReport();
hbosbf8d3e52017-02-28 06:34:47 -08001569 expected_pair.total_round_trip_time = 7.331;
1570 expected_pair.current_round_trip_time = 1.337;
1571 ASSERT_TRUE(report->Get(expected_pair.id()));
1572 EXPECT_EQ(
1573 expected_pair,
1574 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
1575 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
1576
hbos338f78a2017-02-07 06:41:21 -08001577 // Make pair the current pair, clear bandwidth and "GetStats" again.
Jonas Oreland149dc722019-08-28 08:10:27 +02001578 transport_channel_stats.ice_transport_stats.connection_infos[0]
1579 .best_connection = true;
Steve Anton5b387312018-02-02 16:00:20 -08001580 pc_->SetTransportStats(kTransportName, transport_channel_stats);
1581 report = stats_->GetFreshStatsReport();
hbos338f78a2017-02-07 06:41:21 -08001582 // |expected_pair.available_[outgoing/incoming]_bitrate| should still be
1583 // undefined because bandwidth is not set.
1584 ASSERT_TRUE(report->Get(expected_pair.id()));
1585 EXPECT_EQ(
1586 expected_pair,
1587 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
1588 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
1589
1590 // Set bandwidth and "GetStats" again.
stefanf79ade12017-06-02 06:44:03 -07001591 webrtc::Call::Stats call_stats;
1592 const int kSendBandwidth = 888;
1593 call_stats.send_bandwidth_bps = kSendBandwidth;
1594 const int kRecvBandwidth = 999;
1595 call_stats.recv_bandwidth_bps = kRecvBandwidth;
Steve Anton5b387312018-02-02 16:00:20 -08001596 pc_->SetCallStats(call_stats);
1597 report = stats_->GetFreshStatsReport();
stefanf79ade12017-06-02 06:44:03 -07001598 expected_pair.available_outgoing_bitrate = kSendBandwidth;
1599 expected_pair.available_incoming_bitrate = kRecvBandwidth;
hbos338f78a2017-02-07 06:41:21 -08001600 ASSERT_TRUE(report->Get(expected_pair.id()));
1601 EXPECT_EQ(
1602 expected_pair,
1603 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
1604 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
1605
hbosc42ba322016-12-21 03:31:45 -08001606 RTCLocalIceCandidateStats expected_local_candidate(
1607 *expected_pair.local_candidate_id, report->timestamp_us());
hbosb4e426e2017-01-02 09:59:31 -08001608 expected_local_candidate.transport_id = *expected_pair.transport_id;
Gary Liu37e489c2017-11-21 10:49:36 -08001609 expected_local_candidate.network_type = "wifi";
hbosc42ba322016-12-21 03:31:45 -08001610 expected_local_candidate.ip = "42.42.42.42";
Philipp Hanckea9ba4502021-03-22 13:22:54 +01001611 expected_local_candidate.address = "42.42.42.42";
hbosc42ba322016-12-21 03:31:45 -08001612 expected_local_candidate.port = 42;
1613 expected_local_candidate.protocol = "protocol";
1614 expected_local_candidate.candidate_type = "host";
1615 expected_local_candidate.priority = 42;
Jonas Oreland0d13bbd2022-03-02 11:17:36 +01001616 expected_local_candidate.vpn = false;
1617 expected_local_candidate.network_adapter_type = RTCNetworkAdapterType::kWifi;
hbosc42ba322016-12-21 03:31:45 -08001618 ASSERT_TRUE(report->Get(expected_local_candidate.id()));
1619 EXPECT_EQ(expected_local_candidate,
Yves Gerey665174f2018-06-19 15:03:05 +02001620 report->Get(expected_local_candidate.id())
1621 ->cast_to<RTCLocalIceCandidateStats>());
hbosc42ba322016-12-21 03:31:45 -08001622
1623 RTCRemoteIceCandidateStats expected_remote_candidate(
1624 *expected_pair.remote_candidate_id, report->timestamp_us());
hbosb4e426e2017-01-02 09:59:31 -08001625 expected_remote_candidate.transport_id = *expected_pair.transport_id;
hbosc42ba322016-12-21 03:31:45 -08001626 expected_remote_candidate.ip = "42.42.42.42";
Philipp Hanckea9ba4502021-03-22 13:22:54 +01001627 expected_remote_candidate.address = "42.42.42.42";
hbosc42ba322016-12-21 03:31:45 -08001628 expected_remote_candidate.port = 42;
1629 expected_remote_candidate.protocol = "protocol";
1630 expected_remote_candidate.candidate_type = "host";
1631 expected_remote_candidate.priority = 42;
1632 ASSERT_TRUE(report->Get(expected_remote_candidate.id()));
1633 EXPECT_EQ(expected_remote_candidate,
Yves Gerey665174f2018-06-19 15:03:05 +02001634 report->Get(expected_remote_candidate.id())
1635 ->cast_to<RTCRemoteIceCandidateStats>());
hbosc47a0c32016-10-11 14:54:49 -07001636}
1637
hbosd565b732016-08-30 14:04:35 -07001638TEST_F(RTCStatsCollectorTest, CollectRTCPeerConnectionStats) {
hbosd565b732016-08-30 14:04:35 -07001639 {
Steve Anton5b387312018-02-02 16:00:20 -08001640 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos82ebe022016-11-14 01:41:09 -08001641 RTCPeerConnectionStats expected("RTCPeerConnection",
1642 report->timestamp_us());
1643 expected.data_channels_opened = 0;
1644 expected.data_channels_closed = 0;
hbosdbb64d82016-12-21 01:57:46 -08001645 ASSERT_TRUE(report->Get("RTCPeerConnection"));
Yves Gerey665174f2018-06-19 15:03:05 +02001646 EXPECT_EQ(
1647 expected,
1648 report->Get("RTCPeerConnection")->cast_to<RTCPeerConnectionStats>());
hbosd565b732016-08-30 14:04:35 -07001649 }
1650
Tomas Gunnarsson7d3cfbf2020-06-15 13:47:42 +02001651 // TODO(bugs.webrtc.org/11547): Supply a separate network thread.
Taylor Brandstetter3a034e12020-07-09 15:32:34 -07001652 FakeDataChannelProvider provider;
1653 rtc::scoped_refptr<SctpDataChannel> dummy_channel_a = SctpDataChannel::Create(
1654 &provider, "DummyChannelA", InternalDataChannelInit(),
Tomas Gunnarsson7d3cfbf2020-06-15 13:47:42 +02001655 rtc::Thread::Current(), rtc::Thread::Current());
Mirko Bonadeie0bc8d22022-02-08 07:41:25 +00001656 pc_->SignalSctpDataChannelCreated()(dummy_channel_a.get());
Taylor Brandstetter3a034e12020-07-09 15:32:34 -07001657 rtc::scoped_refptr<SctpDataChannel> dummy_channel_b = SctpDataChannel::Create(
1658 &provider, "DummyChannelB", InternalDataChannelInit(),
Tomas Gunnarsson7d3cfbf2020-06-15 13:47:42 +02001659 rtc::Thread::Current(), rtc::Thread::Current());
Mirko Bonadeie0bc8d22022-02-08 07:41:25 +00001660 pc_->SignalSctpDataChannelCreated()(dummy_channel_b.get());
hbosd565b732016-08-30 14:04:35 -07001661
hbos82ebe022016-11-14 01:41:09 -08001662 dummy_channel_a->SignalOpened(dummy_channel_a.get());
1663 // Closing a channel that is not opened should not affect the counts.
1664 dummy_channel_b->SignalClosed(dummy_channel_b.get());
1665
hbosd565b732016-08-30 14:04:35 -07001666 {
Steve Anton5b387312018-02-02 16:00:20 -08001667 rtc::scoped_refptr<const RTCStatsReport> report =
1668 stats_->GetFreshStatsReport();
hbos82ebe022016-11-14 01:41:09 -08001669 RTCPeerConnectionStats expected("RTCPeerConnection",
1670 report->timestamp_us());
1671 expected.data_channels_opened = 1;
1672 expected.data_channels_closed = 0;
hbosdbb64d82016-12-21 01:57:46 -08001673 ASSERT_TRUE(report->Get("RTCPeerConnection"));
Yves Gerey665174f2018-06-19 15:03:05 +02001674 EXPECT_EQ(
1675 expected,
1676 report->Get("RTCPeerConnection")->cast_to<RTCPeerConnectionStats>());
hbos82ebe022016-11-14 01:41:09 -08001677 }
1678
1679 dummy_channel_b->SignalOpened(dummy_channel_b.get());
1680 dummy_channel_b->SignalClosed(dummy_channel_b.get());
1681
1682 {
Steve Anton5b387312018-02-02 16:00:20 -08001683 rtc::scoped_refptr<const RTCStatsReport> report =
1684 stats_->GetFreshStatsReport();
hbos82ebe022016-11-14 01:41:09 -08001685 RTCPeerConnectionStats expected("RTCPeerConnection",
1686 report->timestamp_us());
1687 expected.data_channels_opened = 2;
1688 expected.data_channels_closed = 1;
hbosdbb64d82016-12-21 01:57:46 -08001689 ASSERT_TRUE(report->Get("RTCPeerConnection"));
Yves Gerey665174f2018-06-19 15:03:05 +02001690 EXPECT_EQ(
1691 expected,
1692 report->Get("RTCPeerConnection")->cast_to<RTCPeerConnectionStats>());
hbosd565b732016-08-30 14:04:35 -07001693 }
hbos5bf9def2017-03-20 03:14:14 -07001694
1695 // Re-opening a data channel (or opening a new data channel that is re-using
1696 // the same address in memory) should increase the opened count.
1697 dummy_channel_b->SignalOpened(dummy_channel_b.get());
1698
1699 {
Steve Anton5b387312018-02-02 16:00:20 -08001700 rtc::scoped_refptr<const RTCStatsReport> report =
1701 stats_->GetFreshStatsReport();
hbos5bf9def2017-03-20 03:14:14 -07001702 RTCPeerConnectionStats expected("RTCPeerConnection",
1703 report->timestamp_us());
1704 expected.data_channels_opened = 3;
1705 expected.data_channels_closed = 1;
1706 ASSERT_TRUE(report->Get("RTCPeerConnection"));
Yves Gerey665174f2018-06-19 15:03:05 +02001707 EXPECT_EQ(
1708 expected,
1709 report->Get("RTCPeerConnection")->cast_to<RTCPeerConnectionStats>());
hbos5bf9def2017-03-20 03:14:14 -07001710 }
1711
1712 dummy_channel_a->SignalClosed(dummy_channel_a.get());
1713 dummy_channel_b->SignalClosed(dummy_channel_b.get());
1714
1715 {
Steve Anton5b387312018-02-02 16:00:20 -08001716 rtc::scoped_refptr<const RTCStatsReport> report =
1717 stats_->GetFreshStatsReport();
hbos5bf9def2017-03-20 03:14:14 -07001718 RTCPeerConnectionStats expected("RTCPeerConnection",
1719 report->timestamp_us());
1720 expected.data_channels_opened = 3;
1721 expected.data_channels_closed = 3;
1722 ASSERT_TRUE(report->Get("RTCPeerConnection"));
Yves Gerey665174f2018-06-19 15:03:05 +02001723 EXPECT_EQ(
1724 expected,
1725 report->Get("RTCPeerConnection")->cast_to<RTCPeerConnectionStats>());
hbos5bf9def2017-03-20 03:14:14 -07001726 }
hbosd565b732016-08-30 14:04:35 -07001727}
1728
hbos09bc1282016-11-08 06:29:22 -08001729TEST_F(RTCStatsCollectorTest,
Harald Alvestranda3dab842018-01-14 09:18:58 +01001730 CollectLocalRTCMediaStreamStatsAndRTCMediaStreamTrackStats_Audio) {
hbos09bc1282016-11-08 06:29:22 -08001731 rtc::scoped_refptr<MediaStream> local_stream =
Seth Hampson845e8782018-03-02 11:34:10 -08001732 MediaStream::Create("LocalStreamId");
Steve Anton5b387312018-02-02 16:00:20 -08001733 pc_->mutable_local_streams()->AddStream(local_stream);
hbos09bc1282016-11-08 06:29:22 -08001734
1735 // Local audio track
hbos9e302742017-01-20 02:47:10 -08001736 rtc::scoped_refptr<MediaStreamTrackInterface> local_audio_track =
1737 CreateFakeTrack(cricket::MEDIA_TYPE_AUDIO, "LocalAudioTrackID",
1738 MediaStreamTrackInterface::kEnded);
Harald Alvestrand2f7ad282022-04-21 11:35:43 +00001739 local_stream->AddTrack(rtc::scoped_refptr<AudioTrackInterface>(
1740 static_cast<AudioTrackInterface*>(local_audio_track.get())));
hbos9e302742017-01-20 02:47:10 -08001741
1742 cricket::VoiceSenderInfo voice_sender_info_ssrc1;
1743 voice_sender_info_ssrc1.local_stats.push_back(cricket::SsrcSenderInfo());
1744 voice_sender_info_ssrc1.local_stats[0].ssrc = 1;
Ivo Creusen56d46092017-11-24 17:29:59 +01001745 voice_sender_info_ssrc1.apm_statistics.echo_return_loss = 42.0;
1746 voice_sender_info_ssrc1.apm_statistics.echo_return_loss_enhancement = 52.0;
hbos9e302742017-01-20 02:47:10 -08001747
Steve Anton5b387312018-02-02 16:00:20 -08001748 stats_->CreateMockRtpSendersReceiversAndChannels(
Harald Alvestranda3dab842018-01-14 09:18:58 +01001749 {std::make_pair(local_audio_track.get(), voice_sender_info_ssrc1)}, {},
Seth Hampson13b8bad2018-03-13 16:05:28 -07001750 {}, {}, {local_stream->id()}, {});
Harald Alvestranda3dab842018-01-14 09:18:58 +01001751
Steve Anton5b387312018-02-02 16:00:20 -08001752 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Harald Alvestranda3dab842018-01-14 09:18:58 +01001753
1754 RTCMediaStreamStats expected_local_stream(
Niels Möllerafb246b2022-04-20 14:26:50 +02001755 IdForType<RTCMediaStreamStats>(report.get()), report->timestamp_us());
Seth Hampson13b8bad2018-03-13 16:05:28 -07001756 expected_local_stream.stream_identifier = local_stream->id();
Harald Alvestranda3dab842018-01-14 09:18:58 +01001757 expected_local_stream.track_ids = {
Niels Möllerafb246b2022-04-20 14:26:50 +02001758 IdForType<RTCMediaStreamTrackStats>(report.get())};
Harald Alvestranda3dab842018-01-14 09:18:58 +01001759 ASSERT_TRUE(report->Get(expected_local_stream.id()))
1760 << "Did not find " << expected_local_stream.id() << " in "
1761 << report->ToJson();
1762 EXPECT_EQ(
1763 expected_local_stream,
1764 report->Get(expected_local_stream.id())->cast_to<RTCMediaStreamStats>());
1765
1766 RTCMediaStreamTrackStats expected_local_audio_track_ssrc1(
Niels Möllerafb246b2022-04-20 14:26:50 +02001767 IdForType<RTCMediaStreamTrackStats>(report.get()), report->timestamp_us(),
Harald Alvestranda3dab842018-01-14 09:18:58 +01001768 RTCMediaStreamTrackKind::kAudio);
1769 expected_local_audio_track_ssrc1.track_identifier = local_audio_track->id();
Henrik Boström646fda02019-05-22 15:49:42 +02001770 expected_local_audio_track_ssrc1.media_source_id =
1771 "RTCAudioSource_11"; // Attachment ID = SSRC + 10
Harald Alvestranda3dab842018-01-14 09:18:58 +01001772 expected_local_audio_track_ssrc1.remote_source = false;
1773 expected_local_audio_track_ssrc1.ended = true;
1774 expected_local_audio_track_ssrc1.detached = false;
Harald Alvestranda3dab842018-01-14 09:18:58 +01001775 expected_local_audio_track_ssrc1.echo_return_loss = 42.0;
1776 expected_local_audio_track_ssrc1.echo_return_loss_enhancement = 52.0;
1777 ASSERT_TRUE(report->Get(expected_local_audio_track_ssrc1.id()))
1778 << "Did not find " << expected_local_audio_track_ssrc1.id() << " in "
1779 << report->ToJson();
1780 EXPECT_EQ(expected_local_audio_track_ssrc1,
1781 report->Get(expected_local_audio_track_ssrc1.id())
1782 ->cast_to<RTCMediaStreamTrackStats>());
1783}
1784
1785TEST_F(RTCStatsCollectorTest,
1786 CollectRemoteRTCMediaStreamStatsAndRTCMediaStreamTrackStats_Audio) {
Harald Alvestranda3dab842018-01-14 09:18:58 +01001787 rtc::scoped_refptr<MediaStream> remote_stream =
Seth Hampson845e8782018-03-02 11:34:10 -08001788 MediaStream::Create("RemoteStreamId");
Steve Anton5b387312018-02-02 16:00:20 -08001789 pc_->mutable_remote_streams()->AddStream(remote_stream);
Harald Alvestranda3dab842018-01-14 09:18:58 +01001790
hbos09bc1282016-11-08 06:29:22 -08001791 // Remote audio track
hbos9e302742017-01-20 02:47:10 -08001792 rtc::scoped_refptr<MediaStreamTrackInterface> remote_audio_track =
1793 CreateFakeTrack(cricket::MEDIA_TYPE_AUDIO, "RemoteAudioTrackID",
1794 MediaStreamTrackInterface::kLive);
Harald Alvestrand2f7ad282022-04-21 11:35:43 +00001795 remote_stream->AddTrack(rtc::scoped_refptr<AudioTrackInterface>(
1796 static_cast<AudioTrackInterface*>(remote_audio_track.get())));
hbos9e302742017-01-20 02:47:10 -08001797
1798 cricket::VoiceReceiverInfo voice_receiver_info;
1799 voice_receiver_info.local_stats.push_back(cricket::SsrcReceiverInfo());
1800 voice_receiver_info.local_stats[0].ssrc = 3;
Philipp Hanckeaa83cc72020-10-27 09:50:36 +01001801 voice_receiver_info.audio_level = 16383; // [0,32767]
zsteine76bd3a2017-07-14 12:17:49 -07001802 voice_receiver_info.total_output_energy = 0.125;
Steve Anton2dbc69f2017-08-24 17:15:13 -07001803 voice_receiver_info.total_samples_received = 4567;
zsteine76bd3a2017-07-14 12:17:49 -07001804 voice_receiver_info.total_output_duration = 0.25;
Steve Anton2dbc69f2017-08-24 17:15:13 -07001805 voice_receiver_info.concealed_samples = 123;
Gustaf Ullberg9a2e9062017-09-18 09:28:20 +02001806 voice_receiver_info.concealment_events = 12;
Ivo Creusen8d8ffdb2019-04-30 09:45:21 +02001807 voice_receiver_info.inserted_samples_for_deceleration = 987;
1808 voice_receiver_info.removed_samples_for_acceleration = 876;
1809 voice_receiver_info.silent_concealed_samples = 765;
Byoungchan Lee899b29e2021-06-29 22:09:18 +09001810 voice_receiver_info.jitter_buffer_delay_seconds = 3.456;
Chen Xing0acffb52019-01-15 15:46:29 +01001811 voice_receiver_info.jitter_buffer_emitted_count = 13;
Artem Titove618cc92020-03-11 11:18:54 +01001812 voice_receiver_info.jitter_buffer_target_delay_seconds = 7.894;
Ruslan Burakov8af88962018-11-22 17:21:10 +01001813 voice_receiver_info.jitter_buffer_flushes = 7;
Jakob Ivarsson352ce5c2018-11-27 12:52:16 +01001814 voice_receiver_info.delayed_packet_outage_samples = 15;
Jakob Ivarsson232b3fd2019-03-06 09:18:40 +01001815 voice_receiver_info.relative_packet_arrival_delay_seconds = 16;
Henrik Lundin44125fa2019-04-29 17:00:46 +02001816 voice_receiver_info.interruption_count = 7788;
1817 voice_receiver_info.total_interruption_duration_ms = 778899;
hbos9e302742017-01-20 02:47:10 -08001818
Steve Anton5b387312018-02-02 16:00:20 -08001819 stats_->CreateMockRtpSendersReceiversAndChannels(
Harald Alvestranda3dab842018-01-14 09:18:58 +01001820 {}, {std::make_pair(remote_audio_track.get(), voice_receiver_info)}, {},
1821 {}, {}, {remote_stream});
hbos09bc1282016-11-08 06:29:22 -08001822
Steve Anton5b387312018-02-02 16:00:20 -08001823 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos09bc1282016-11-08 06:29:22 -08001824
hbos09bc1282016-11-08 06:29:22 -08001825 RTCMediaStreamStats expected_remote_stream(
Niels Möllerafb246b2022-04-20 14:26:50 +02001826 IdForType<RTCMediaStreamStats>(report.get()), report->timestamp_us());
Seth Hampson13b8bad2018-03-13 16:05:28 -07001827 expected_remote_stream.stream_identifier = remote_stream->id();
Niels Möllerafb246b2022-04-20 14:26:50 +02001828 expected_remote_stream.track_ids = std::vector<std::string>(
1829 {IdForType<RTCMediaStreamTrackStats>(report.get())});
Harald Alvestranda3dab842018-01-14 09:18:58 +01001830 ASSERT_TRUE(report->Get(expected_remote_stream.id()))
1831 << "Did not find " << expected_remote_stream.id() << " in "
1832 << report->ToJson();
Yves Gerey665174f2018-06-19 15:03:05 +02001833 EXPECT_EQ(
1834 expected_remote_stream,
1835 report->Get(expected_remote_stream.id())->cast_to<RTCMediaStreamStats>());
hbos09bc1282016-11-08 06:29:22 -08001836
hbos09bc1282016-11-08 06:29:22 -08001837 RTCMediaStreamTrackStats expected_remote_audio_track(
Niels Möllerafb246b2022-04-20 14:26:50 +02001838 IdForType<RTCMediaStreamTrackStats>(report.get()), report->timestamp_us(),
Harald Alvestranda3dab842018-01-14 09:18:58 +01001839 RTCMediaStreamTrackKind::kAudio);
hbos09bc1282016-11-08 06:29:22 -08001840 expected_remote_audio_track.track_identifier = remote_audio_track->id();
Artem Titovcfea2182021-08-10 01:22:31 +02001841 // `expected_remote_audio_track.media_source_id` should be undefined
Henrik Boström646fda02019-05-22 15:49:42 +02001842 // because the track is remote.
hbos09bc1282016-11-08 06:29:22 -08001843 expected_remote_audio_track.remote_source = true;
1844 expected_remote_audio_track.ended = false;
1845 expected_remote_audio_track.detached = false;
Philipp Hanckeaa83cc72020-10-27 09:50:36 +01001846 expected_remote_audio_track.audio_level = 16383.0 / 32767.0; // [0,1]
zsteine76bd3a2017-07-14 12:17:49 -07001847 expected_remote_audio_track.total_audio_energy = 0.125;
Steve Anton2dbc69f2017-08-24 17:15:13 -07001848 expected_remote_audio_track.total_samples_received = 4567;
zsteine76bd3a2017-07-14 12:17:49 -07001849 expected_remote_audio_track.total_samples_duration = 0.25;
Steve Anton2dbc69f2017-08-24 17:15:13 -07001850 expected_remote_audio_track.concealed_samples = 123;
Gustaf Ullberg9a2e9062017-09-18 09:28:20 +02001851 expected_remote_audio_track.concealment_events = 12;
Ivo Creusen8d8ffdb2019-04-30 09:45:21 +02001852 expected_remote_audio_track.inserted_samples_for_deceleration = 987;
1853 expected_remote_audio_track.removed_samples_for_acceleration = 876;
1854 expected_remote_audio_track.silent_concealed_samples = 765;
Byoungchan Lee899b29e2021-06-29 22:09:18 +09001855 expected_remote_audio_track.jitter_buffer_delay = 3.456;
Chen Xing0acffb52019-01-15 15:46:29 +01001856 expected_remote_audio_track.jitter_buffer_emitted_count = 13;
Artem Titove618cc92020-03-11 11:18:54 +01001857 expected_remote_audio_track.jitter_buffer_target_delay = 7.894;
Ruslan Burakov8af88962018-11-22 17:21:10 +01001858 expected_remote_audio_track.jitter_buffer_flushes = 7;
Jakob Ivarsson352ce5c2018-11-27 12:52:16 +01001859 expected_remote_audio_track.delayed_packet_outage_samples = 15;
Jakob Ivarsson232b3fd2019-03-06 09:18:40 +01001860 expected_remote_audio_track.relative_packet_arrival_delay = 16;
Henrik Lundin44125fa2019-04-29 17:00:46 +02001861 expected_remote_audio_track.interruption_count = 7788;
1862 expected_remote_audio_track.total_interruption_duration = 778.899;
hbosdbb64d82016-12-21 01:57:46 -08001863 ASSERT_TRUE(report->Get(expected_remote_audio_track.id()));
hbos09bc1282016-11-08 06:29:22 -08001864 EXPECT_EQ(expected_remote_audio_track,
Yves Gerey665174f2018-06-19 15:03:05 +02001865 report->Get(expected_remote_audio_track.id())
1866 ->cast_to<RTCMediaStreamTrackStats>());
hbos09bc1282016-11-08 06:29:22 -08001867}
1868
1869TEST_F(RTCStatsCollectorTest,
Harald Alvestranda3dab842018-01-14 09:18:58 +01001870 CollectLocalRTCMediaStreamStatsAndRTCMediaStreamTrackStats_Video) {
hbos09bc1282016-11-08 06:29:22 -08001871 rtc::scoped_refptr<MediaStream> local_stream =
Seth Hampson845e8782018-03-02 11:34:10 -08001872 MediaStream::Create("LocalStreamId");
Steve Anton5b387312018-02-02 16:00:20 -08001873 pc_->mutable_local_streams()->AddStream(local_stream);
hbos09bc1282016-11-08 06:29:22 -08001874
1875 // Local video track
hbos9e302742017-01-20 02:47:10 -08001876 rtc::scoped_refptr<MediaStreamTrackInterface> local_video_track =
1877 CreateFakeTrack(cricket::MEDIA_TYPE_VIDEO, "LocalVideoTrackID",
1878 MediaStreamTrackInterface::kLive);
Harald Alvestrand2f7ad282022-04-21 11:35:43 +00001879 local_stream->AddTrack(rtc::scoped_refptr<VideoTrackInterface>(
1880 static_cast<VideoTrackInterface*>(local_video_track.get())));
hbos09bc1282016-11-08 06:29:22 -08001881
hbos9e302742017-01-20 02:47:10 -08001882 cricket::VideoSenderInfo video_sender_info_ssrc1;
1883 video_sender_info_ssrc1.local_stats.push_back(cricket::SsrcSenderInfo());
1884 video_sender_info_ssrc1.local_stats[0].ssrc = 1;
1885 video_sender_info_ssrc1.send_frame_width = 1234;
1886 video_sender_info_ssrc1.send_frame_height = 4321;
hbosfefe0762017-01-20 06:14:25 -08001887 video_sender_info_ssrc1.frames_encoded = 11;
Ilya Nikolaevskiy70473fc2018-02-28 16:35:03 +01001888 video_sender_info_ssrc1.huge_frames_sent = 1;
hbos9e302742017-01-20 02:47:10 -08001889
Steve Anton5b387312018-02-02 16:00:20 -08001890 stats_->CreateMockRtpSendersReceiversAndChannels(
Harald Alvestranda3dab842018-01-14 09:18:58 +01001891 {}, {},
1892 {std::make_pair(local_video_track.get(), video_sender_info_ssrc1)}, {},
Seth Hampson13b8bad2018-03-13 16:05:28 -07001893 {local_stream->id()}, {});
Harald Alvestranda3dab842018-01-14 09:18:58 +01001894
Steve Anton5b387312018-02-02 16:00:20 -08001895 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Harald Alvestranda3dab842018-01-14 09:18:58 +01001896
1897 auto stats_of_my_type = report->GetStatsOfType<RTCMediaStreamStats>();
Mirko Bonadeie12c1fe2018-07-03 12:53:23 +02001898 ASSERT_EQ(1U, stats_of_my_type.size()) << "No stream in " << report->ToJson();
Harald Alvestranda3dab842018-01-14 09:18:58 +01001899 auto stats_of_track_type = report->GetStatsOfType<RTCMediaStreamTrackStats>();
Mirko Bonadeie12c1fe2018-07-03 12:53:23 +02001900 ASSERT_EQ(1U, stats_of_track_type.size())
Harald Alvestranda3dab842018-01-14 09:18:58 +01001901 << "Wrong number of tracks in " << report->ToJson();
1902
1903 RTCMediaStreamStats expected_local_stream(stats_of_my_type[0]->id(),
1904 report->timestamp_us());
Seth Hampson13b8bad2018-03-13 16:05:28 -07001905 expected_local_stream.stream_identifier = local_stream->id();
Harald Alvestranda3dab842018-01-14 09:18:58 +01001906 expected_local_stream.track_ids =
1907 std::vector<std::string>({stats_of_track_type[0]->id()});
1908 ASSERT_TRUE(report->Get(expected_local_stream.id()));
1909 EXPECT_EQ(
1910 expected_local_stream,
1911 report->Get(expected_local_stream.id())->cast_to<RTCMediaStreamStats>());
1912
1913 RTCMediaStreamTrackStats expected_local_video_track_ssrc1(
1914 stats_of_track_type[0]->id(), report->timestamp_us(),
1915 RTCMediaStreamTrackKind::kVideo);
1916 expected_local_video_track_ssrc1.track_identifier = local_video_track->id();
Henrik Boström646fda02019-05-22 15:49:42 +02001917 expected_local_video_track_ssrc1.media_source_id =
1918 "RTCVideoSource_11"; // Attachment ID = SSRC + 10
Harald Alvestranda3dab842018-01-14 09:18:58 +01001919 expected_local_video_track_ssrc1.remote_source = false;
1920 expected_local_video_track_ssrc1.ended = false;
1921 expected_local_video_track_ssrc1.detached = false;
1922 expected_local_video_track_ssrc1.frame_width = 1234;
1923 expected_local_video_track_ssrc1.frame_height = 4321;
1924 expected_local_video_track_ssrc1.frames_sent = 11;
Ilya Nikolaevskiy70473fc2018-02-28 16:35:03 +01001925 expected_local_video_track_ssrc1.huge_frames_sent = 1;
Harald Alvestranda3dab842018-01-14 09:18:58 +01001926 ASSERT_TRUE(report->Get(expected_local_video_track_ssrc1.id()));
1927 EXPECT_EQ(expected_local_video_track_ssrc1,
1928 report->Get(expected_local_video_track_ssrc1.id())
1929 ->cast_to<RTCMediaStreamTrackStats>());
1930}
1931
1932TEST_F(RTCStatsCollectorTest,
1933 CollectRemoteRTCMediaStreamStatsAndRTCMediaStreamTrackStats_Video) {
Harald Alvestranda3dab842018-01-14 09:18:58 +01001934 rtc::scoped_refptr<MediaStream> remote_stream =
Seth Hampson845e8782018-03-02 11:34:10 -08001935 MediaStream::Create("RemoteStreamId");
Steve Anton5b387312018-02-02 16:00:20 -08001936 pc_->mutable_remote_streams()->AddStream(remote_stream);
Harald Alvestranda3dab842018-01-14 09:18:58 +01001937
hbos9e302742017-01-20 02:47:10 -08001938 // Remote video track with values
1939 rtc::scoped_refptr<MediaStreamTrackInterface> remote_video_track_ssrc3 =
1940 CreateFakeTrack(cricket::MEDIA_TYPE_VIDEO, "RemoteVideoTrackID3",
1941 MediaStreamTrackInterface::kEnded);
Harald Alvestrand2f7ad282022-04-21 11:35:43 +00001942 remote_stream->AddTrack(rtc::scoped_refptr<VideoTrackInterface>(
1943 static_cast<VideoTrackInterface*>(remote_video_track_ssrc3.get())));
hbos9e302742017-01-20 02:47:10 -08001944
1945 cricket::VideoReceiverInfo video_receiver_info_ssrc3;
1946 video_receiver_info_ssrc3.local_stats.push_back(cricket::SsrcReceiverInfo());
1947 video_receiver_info_ssrc3.local_stats[0].ssrc = 3;
1948 video_receiver_info_ssrc3.frame_width = 6789;
1949 video_receiver_info_ssrc3.frame_height = 9876;
Guido Urdaneta67378412019-05-28 17:38:08 +02001950 video_receiver_info_ssrc3.jitter_buffer_delay_seconds = 2.5;
1951 video_receiver_info_ssrc3.jitter_buffer_emitted_count = 25;
hbos50cfe1f2017-01-23 07:21:55 -08001952 video_receiver_info_ssrc3.frames_received = 1000;
1953 video_receiver_info_ssrc3.frames_decoded = 995;
Johannes Kron0c141c52019-08-26 15:04:43 +02001954 video_receiver_info_ssrc3.frames_dropped = 10;
hbos50cfe1f2017-01-23 07:21:55 -08001955 video_receiver_info_ssrc3.frames_rendered = 990;
Sergey Silkin02371062019-01-31 16:45:42 +01001956 video_receiver_info_ssrc3.freeze_count = 3;
1957 video_receiver_info_ssrc3.pause_count = 2;
1958 video_receiver_info_ssrc3.total_freezes_duration_ms = 1000;
1959 video_receiver_info_ssrc3.total_pauses_duration_ms = 10000;
1960 video_receiver_info_ssrc3.total_frames_duration_ms = 15000;
1961 video_receiver_info_ssrc3.sum_squared_frame_durations = 1.5;
hbos9e302742017-01-20 02:47:10 -08001962
Steve Anton5b387312018-02-02 16:00:20 -08001963 stats_->CreateMockRtpSendersReceiversAndChannels(
Harald Alvestranda3dab842018-01-14 09:18:58 +01001964 {}, {}, {},
Harald Alvestrandc72af932018-01-11 17:18:19 +01001965 {std::make_pair(remote_video_track_ssrc3.get(),
Harald Alvestranda3dab842018-01-14 09:18:58 +01001966 video_receiver_info_ssrc3)},
1967 {}, {remote_stream});
hbos09bc1282016-11-08 06:29:22 -08001968
Steve Anton5b387312018-02-02 16:00:20 -08001969 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos09bc1282016-11-08 06:29:22 -08001970
Harald Alvestranda3dab842018-01-14 09:18:58 +01001971 auto stats_of_my_type = report->GetStatsOfType<RTCMediaStreamStats>();
Mirko Bonadeie12c1fe2018-07-03 12:53:23 +02001972 ASSERT_EQ(1U, stats_of_my_type.size()) << "No stream in " << report->ToJson();
Harald Alvestranda3dab842018-01-14 09:18:58 +01001973 auto stats_of_track_type = report->GetStatsOfType<RTCMediaStreamTrackStats>();
Mirko Bonadeie12c1fe2018-07-03 12:53:23 +02001974 ASSERT_EQ(1U, stats_of_track_type.size())
Harald Alvestranda3dab842018-01-14 09:18:58 +01001975 << "Wrong number of tracks in " << report->ToJson();
1976 ASSERT_TRUE(*(stats_of_track_type[0]->remote_source));
hbos09bc1282016-11-08 06:29:22 -08001977
Harald Alvestranda3dab842018-01-14 09:18:58 +01001978 RTCMediaStreamStats expected_remote_stream(stats_of_my_type[0]->id(),
1979 report->timestamp_us());
Seth Hampson13b8bad2018-03-13 16:05:28 -07001980 expected_remote_stream.stream_identifier = remote_stream->id();
Harald Alvestranda3dab842018-01-14 09:18:58 +01001981 expected_remote_stream.track_ids =
1982 std::vector<std::string>({stats_of_track_type[0]->id()});
hbosdbb64d82016-12-21 01:57:46 -08001983 ASSERT_TRUE(report->Get(expected_remote_stream.id()));
Yves Gerey665174f2018-06-19 15:03:05 +02001984 EXPECT_EQ(
1985 expected_remote_stream,
1986 report->Get(expected_remote_stream.id())->cast_to<RTCMediaStreamStats>());
hbos09bc1282016-11-08 06:29:22 -08001987
hbos9e302742017-01-20 02:47:10 -08001988 RTCMediaStreamTrackStats expected_remote_video_track_ssrc3(
Harald Alvestranda3dab842018-01-14 09:18:58 +01001989 stats_of_track_type[0]->id(), report->timestamp_us(),
1990 RTCMediaStreamTrackKind::kVideo);
hbos9e302742017-01-20 02:47:10 -08001991 expected_remote_video_track_ssrc3.track_identifier =
1992 remote_video_track_ssrc3->id();
Artem Titovcfea2182021-08-10 01:22:31 +02001993 // `expected_remote_video_track_ssrc3.media_source_id` should be undefined
Henrik Boström646fda02019-05-22 15:49:42 +02001994 // because the track is remote.
hbos9e302742017-01-20 02:47:10 -08001995 expected_remote_video_track_ssrc3.remote_source = true;
1996 expected_remote_video_track_ssrc3.ended = true;
1997 expected_remote_video_track_ssrc3.detached = false;
1998 expected_remote_video_track_ssrc3.frame_width = 6789;
1999 expected_remote_video_track_ssrc3.frame_height = 9876;
Guido Urdaneta67378412019-05-28 17:38:08 +02002000 expected_remote_video_track_ssrc3.jitter_buffer_delay = 2.5;
2001 expected_remote_video_track_ssrc3.jitter_buffer_emitted_count = 25;
hbos50cfe1f2017-01-23 07:21:55 -08002002 expected_remote_video_track_ssrc3.frames_received = 1000;
2003 expected_remote_video_track_ssrc3.frames_decoded = 995;
Johannes Kron0c141c52019-08-26 15:04:43 +02002004 expected_remote_video_track_ssrc3.frames_dropped = 10;
Sergey Silkin02371062019-01-31 16:45:42 +01002005 expected_remote_video_track_ssrc3.freeze_count = 3;
2006 expected_remote_video_track_ssrc3.pause_count = 2;
2007 expected_remote_video_track_ssrc3.total_freezes_duration = 1;
2008 expected_remote_video_track_ssrc3.total_pauses_duration = 10;
2009 expected_remote_video_track_ssrc3.total_frames_duration = 15;
2010 expected_remote_video_track_ssrc3.sum_squared_frame_durations = 1.5;
2011
hbos9e302742017-01-20 02:47:10 -08002012 ASSERT_TRUE(report->Get(expected_remote_video_track_ssrc3.id()));
2013 EXPECT_EQ(expected_remote_video_track_ssrc3,
Yves Gerey665174f2018-06-19 15:03:05 +02002014 report->Get(expected_remote_video_track_ssrc3.id())
2015 ->cast_to<RTCMediaStreamTrackStats>());
hbos09bc1282016-11-08 06:29:22 -08002016}
2017
hboseeafe942016-11-01 03:00:17 -07002018TEST_F(RTCStatsCollectorTest, CollectRTCInboundRTPStreamStats_Audio) {
hboseeafe942016-11-01 03:00:17 -07002019 cricket::VoiceMediaInfo voice_media_info;
hbos0adb8282016-11-23 02:32:06 -08002020
hboseeafe942016-11-01 03:00:17 -07002021 voice_media_info.receivers.push_back(cricket::VoiceReceiverInfo());
2022 voice_media_info.receivers[0].local_stats.push_back(
2023 cricket::SsrcReceiverInfo());
2024 voice_media_info.receivers[0].local_stats[0].ssrc = 1;
Harald Alvestrand719487e2017-12-13 12:26:04 +01002025 voice_media_info.receivers[0].packets_lost = -1; // Signed per RFC3550
Minyue Li28a2c632021-07-07 15:53:38 +02002026 voice_media_info.receivers[0].packets_discarded = 7788;
hboseeafe942016-11-01 03:00:17 -07002027 voice_media_info.receivers[0].packets_rcvd = 2;
Jakob Ivarssone54914a2021-07-01 11:16:05 +02002028 voice_media_info.receivers[0].nacks_sent = 5;
Ivo Creusen8d8ffdb2019-04-30 09:45:21 +02002029 voice_media_info.receivers[0].fec_packets_discarded = 5566;
2030 voice_media_info.receivers[0].fec_packets_received = 6677;
Niels Möllerac0a4cb2019-10-09 15:01:33 +02002031 voice_media_info.receivers[0].payload_bytes_rcvd = 3;
2032 voice_media_info.receivers[0].header_and_padding_bytes_rcvd = 4;
Oskar Sundbomcbc71b22017-11-16 10:56:07 +01002033 voice_media_info.receivers[0].codec_payload_type = 42;
hboseeafe942016-11-01 03:00:17 -07002034 voice_media_info.receivers[0].jitter_ms = 4500;
Eldar Rello4e5bc9f2020-07-06 14:18:07 +03002035 voice_media_info.receivers[0].jitter_buffer_delay_seconds = 1.0;
2036 voice_media_info.receivers[0].jitter_buffer_emitted_count = 2;
2037 voice_media_info.receivers[0].total_samples_received = 3;
2038 voice_media_info.receivers[0].concealed_samples = 4;
2039 voice_media_info.receivers[0].silent_concealed_samples = 5;
2040 voice_media_info.receivers[0].concealment_events = 6;
2041 voice_media_info.receivers[0].inserted_samples_for_deceleration = 7;
2042 voice_media_info.receivers[0].removed_samples_for_acceleration = 8;
Philipp Hanckeaa83cc72020-10-27 09:50:36 +01002043 voice_media_info.receivers[0].audio_level = 14442; // [0,32767]
Eldar Rello4e5bc9f2020-07-06 14:18:07 +03002044 voice_media_info.receivers[0].total_output_energy = 10.0;
2045 voice_media_info.receivers[0].total_output_duration = 11.0;
2046
Henrik Boström01738c62019-04-15 17:32:00 +02002047 voice_media_info.receivers[0].last_packet_received_timestamp_ms =
2048 absl::nullopt;
hbos0adb8282016-11-23 02:32:06 -08002049
2050 RtpCodecParameters codec_parameters;
2051 codec_parameters.payload_type = 42;
deadbeefe702b302017-02-04 12:09:01 -08002052 codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
2053 codec_parameters.name = "dummy";
Oskar Sundbomcbc71b22017-11-16 10:56:07 +01002054 codec_parameters.clock_rate = 0;
hbos0adb8282016-11-23 02:32:06 -08002055 voice_media_info.receive_codecs.insert(
2056 std::make_pair(codec_parameters.payload_type, codec_parameters));
2057
Tommi19015512022-02-02 11:49:35 +01002058 auto* voice_media_channel =
2059 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Henrik Boström5b3541f2018-03-19 13:52:56 +01002060 stats_->SetupRemoteTrackAndReceiver(
2061 cricket::MEDIA_TYPE_AUDIO, "RemoteAudioTrackID", "RemoteStreamId", 1);
hboseeafe942016-11-01 03:00:17 -07002062
Steve Anton5b387312018-02-02 16:00:20 -08002063 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hboseeafe942016-11-01 03:00:17 -07002064
Harald Alvestranda3dab842018-01-14 09:18:58 +01002065 auto stats_of_track_type = report->GetStatsOfType<RTCMediaStreamTrackStats>();
Mirko Bonadeie12c1fe2018-07-03 12:53:23 +02002066 ASSERT_EQ(1U, stats_of_track_type.size());
Harald Alvestranda3dab842018-01-14 09:18:58 +01002067
Yves Gerey665174f2018-06-19 15:03:05 +02002068 RTCInboundRTPStreamStats expected_audio("RTCInboundRTPAudioStream_1",
2069 report->timestamp_us());
hbos3443bb72017-02-07 06:28:11 -08002070 expected_audio.ssrc = 1;
hboseeafe942016-11-01 03:00:17 -07002071 expected_audio.media_type = "audio";
Philipp Hancke3bc01662018-08-28 14:55:03 +02002072 expected_audio.kind = "audio";
Harald Alvestranda3dab842018-01-14 09:18:58 +01002073 expected_audio.track_id = stats_of_track_type[0]->id();
Steve Anton57858b32018-02-15 15:19:50 -08002074 expected_audio.transport_id = "RTCTransport_TransportName_1";
2075 expected_audio.codec_id = "RTCCodec_AudioMid_Inbound_42";
hboseeafe942016-11-01 03:00:17 -07002076 expected_audio.packets_received = 2;
Jakob Ivarssone54914a2021-07-01 11:16:05 +02002077 expected_audio.nack_count = 5;
Ivo Creusen8d8ffdb2019-04-30 09:45:21 +02002078 expected_audio.fec_packets_discarded = 5566;
2079 expected_audio.fec_packets_received = 6677;
hboseeafe942016-11-01 03:00:17 -07002080 expected_audio.bytes_received = 3;
Niels Möllerac0a4cb2019-10-09 15:01:33 +02002081 expected_audio.header_bytes_received = 4;
Harald Alvestrand719487e2017-12-13 12:26:04 +01002082 expected_audio.packets_lost = -1;
Minyue Li28a2c632021-07-07 15:53:38 +02002083 expected_audio.packets_discarded = 7788;
Artem Titovcfea2182021-08-10 01:22:31 +02002084 // `expected_audio.last_packet_received_timestamp` should be undefined.
hboseeafe942016-11-01 03:00:17 -07002085 expected_audio.jitter = 4.5;
Eldar Rello4e5bc9f2020-07-06 14:18:07 +03002086 expected_audio.jitter_buffer_delay = 1.0;
2087 expected_audio.jitter_buffer_emitted_count = 2;
2088 expected_audio.total_samples_received = 3;
2089 expected_audio.concealed_samples = 4;
2090 expected_audio.silent_concealed_samples = 5;
2091 expected_audio.concealment_events = 6;
2092 expected_audio.inserted_samples_for_deceleration = 7;
2093 expected_audio.removed_samples_for_acceleration = 8;
Philipp Hanckeaa83cc72020-10-27 09:50:36 +01002094 expected_audio.audio_level = 14442.0 / 32767.0; // [0,1]
Eldar Rello4e5bc9f2020-07-06 14:18:07 +03002095 expected_audio.total_audio_energy = 10.0;
2096 expected_audio.total_samples_duration = 11.0;
2097
nissec8ee8822017-01-18 07:20:55 -08002098 ASSERT_TRUE(report->Get(expected_audio.id()));
hbosa51d4f32017-02-16 05:34:48 -08002099 EXPECT_EQ(
2100 report->Get(expected_audio.id())->cast_to<RTCInboundRTPStreamStats>(),
2101 expected_audio);
Henrik Boström01738c62019-04-15 17:32:00 +02002102
2103 // Set previously undefined values and "GetStats" again.
2104 voice_media_info.receivers[0].last_packet_received_timestamp_ms = 3000;
Alessio Bazzicac366d512021-03-22 15:36:53 +01002105 expected_audio.last_packet_received_timestamp = 3000.0;
Åsa Perssonfcf79cc2019-10-22 15:23:44 +02002106 voice_media_info.receivers[0].estimated_playout_ntp_timestamp_ms = 4567;
2107 expected_audio.estimated_playout_timestamp = 4567;
Henrik Boström01738c62019-04-15 17:32:00 +02002108 voice_media_channel->SetStats(voice_media_info);
2109
2110 report = stats_->GetFreshStatsReport();
2111
2112 ASSERT_TRUE(report->Get(expected_audio.id()));
2113 EXPECT_EQ(
2114 report->Get(expected_audio.id())->cast_to<RTCInboundRTPStreamStats>(),
2115 expected_audio);
hbosb0ae9202017-01-27 06:35:16 -08002116 EXPECT_TRUE(report->Get(*expected_audio.track_id));
hbos84abeb12017-01-16 06:16:44 -08002117 EXPECT_TRUE(report->Get(*expected_audio.transport_id));
2118 EXPECT_TRUE(report->Get(*expected_audio.codec_id));
hboseeafe942016-11-01 03:00:17 -07002119}
2120
2121TEST_F(RTCStatsCollectorTest, CollectRTCInboundRTPStreamStats_Video) {
hboseeafe942016-11-01 03:00:17 -07002122 cricket::VideoMediaInfo video_media_info;
hbos0adb8282016-11-23 02:32:06 -08002123
hboseeafe942016-11-01 03:00:17 -07002124 video_media_info.receivers.push_back(cricket::VideoReceiverInfo());
2125 video_media_info.receivers[0].local_stats.push_back(
2126 cricket::SsrcReceiverInfo());
2127 video_media_info.receivers[0].local_stats[0].ssrc = 1;
2128 video_media_info.receivers[0].packets_rcvd = 2;
hbos02cd4d62016-12-09 04:19:44 -08002129 video_media_info.receivers[0].packets_lost = 42;
Niels Möllerac0a4cb2019-10-09 15:01:33 +02002130 video_media_info.receivers[0].payload_bytes_rcvd = 3;
2131 video_media_info.receivers[0].header_and_padding_bytes_rcvd = 12;
Oskar Sundbomcbc71b22017-11-16 10:56:07 +01002132 video_media_info.receivers[0].codec_payload_type = 42;
hbos820f5782016-11-22 03:16:50 -08002133 video_media_info.receivers[0].firs_sent = 5;
2134 video_media_info.receivers[0].plis_sent = 6;
2135 video_media_info.receivers[0].nacks_sent = 7;
Eldar Rello4e5bc9f2020-07-06 14:18:07 +03002136 video_media_info.receivers[0].frames_received = 8;
2137 video_media_info.receivers[0].frames_decoded = 9;
Rasmus Brandt2efae772019-06-27 14:29:34 +02002138 video_media_info.receivers[0].key_frames_decoded = 3;
Eldar Rello4e5bc9f2020-07-06 14:18:07 +03002139 video_media_info.receivers[0].frames_dropped = 13;
Danil Chapovalov66cadcc2018-06-19 16:47:43 +02002140 video_media_info.receivers[0].qp_sum = absl::nullopt;
Johannes Kronbfd343b2019-07-01 10:07:50 +02002141 video_media_info.receivers[0].total_decode_time_ms = 9000;
Philipp Hanckea16a6a62022-04-25 12:21:30 +02002142 video_media_info.receivers[0].total_processing_delay =
2143 webrtc::TimeDelta::Millis(600);
Johannes Kron00376e12019-11-25 10:25:42 +01002144 video_media_info.receivers[0].total_inter_frame_delay = 0.123;
2145 video_media_info.receivers[0].total_squared_inter_frame_delay = 0.00456;
Di Wu (RP Room Eng)8af6b492021-02-19 17:34:22 -08002146 video_media_info.receivers[0].jitter_ms = 1199;
Byoungchan Lee899b29e2021-06-29 22:09:18 +09002147 video_media_info.receivers[0].jitter_buffer_delay_seconds = 3.456;
2148 video_media_info.receivers[0].jitter_buffer_emitted_count = 13;
Johannes Kron00376e12019-11-25 10:25:42 +01002149
Henrik Boström01738c62019-04-15 17:32:00 +02002150 video_media_info.receivers[0].last_packet_received_timestamp_ms =
2151 absl::nullopt;
Henrik Boström2e069262019-04-09 13:59:31 +02002152 video_media_info.receivers[0].content_type = VideoContentType::UNSPECIFIED;
Åsa Perssonfcf79cc2019-10-22 15:23:44 +02002153 video_media_info.receivers[0].estimated_playout_ntp_timestamp_ms =
2154 absl::nullopt;
Henrik Boström6b430862019-08-16 13:09:51 +02002155 video_media_info.receivers[0].decoder_implementation_name = "";
hbos0adb8282016-11-23 02:32:06 -08002156
2157 RtpCodecParameters codec_parameters;
2158 codec_parameters.payload_type = 42;
deadbeefe702b302017-02-04 12:09:01 -08002159 codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
2160 codec_parameters.name = "dummy";
Oskar Sundbomcbc71b22017-11-16 10:56:07 +01002161 codec_parameters.clock_rate = 0;
hbos0adb8282016-11-23 02:32:06 -08002162 video_media_info.receive_codecs.insert(
2163 std::make_pair(codec_parameters.payload_type, codec_parameters));
2164
Tommi19015512022-02-02 11:49:35 +01002165 auto* video_media_channel =
2166 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström5b3541f2018-03-19 13:52:56 +01002167 stats_->SetupRemoteTrackAndReceiver(
2168 cricket::MEDIA_TYPE_VIDEO, "RemoteVideoTrackID", "RemoteStreamId", 1);
hboseeafe942016-11-01 03:00:17 -07002169
Steve Anton5b387312018-02-02 16:00:20 -08002170 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hboseeafe942016-11-01 03:00:17 -07002171
Yves Gerey665174f2018-06-19 15:03:05 +02002172 RTCInboundRTPStreamStats expected_video("RTCInboundRTPVideoStream_1",
2173 report->timestamp_us());
hbos3443bb72017-02-07 06:28:11 -08002174 expected_video.ssrc = 1;
hbos820f5782016-11-22 03:16:50 -08002175 expected_video.media_type = "video";
Philipp Hancke3bc01662018-08-28 14:55:03 +02002176 expected_video.kind = "video";
Niels Möllerafb246b2022-04-20 14:26:50 +02002177 expected_video.track_id = IdForType<RTCMediaStreamTrackStats>(report.get());
Steve Anton57858b32018-02-15 15:19:50 -08002178 expected_video.transport_id = "RTCTransport_TransportName_1";
2179 expected_video.codec_id = "RTCCodec_VideoMid_Inbound_42";
hbos820f5782016-11-22 03:16:50 -08002180 expected_video.fir_count = 5;
2181 expected_video.pli_count = 6;
2182 expected_video.nack_count = 7;
2183 expected_video.packets_received = 2;
2184 expected_video.bytes_received = 3;
Niels Möllerac0a4cb2019-10-09 15:01:33 +02002185 expected_video.header_bytes_received = 12;
hbos02cd4d62016-12-09 04:19:44 -08002186 expected_video.packets_lost = 42;
Eldar Rello4e5bc9f2020-07-06 14:18:07 +03002187 expected_video.frames_received = 8;
2188 expected_video.frames_decoded = 9;
Rasmus Brandt2efae772019-06-27 14:29:34 +02002189 expected_video.key_frames_decoded = 3;
Eldar Rello4e5bc9f2020-07-06 14:18:07 +03002190 expected_video.frames_dropped = 13;
Artem Titovcfea2182021-08-10 01:22:31 +02002191 // `expected_video.qp_sum` should be undefined.
Johannes Kronbfd343b2019-07-01 10:07:50 +02002192 expected_video.total_decode_time = 9.0;
Philipp Hanckea16a6a62022-04-25 12:21:30 +02002193 expected_video.total_processing_delay = 0.6;
Johannes Kron00376e12019-11-25 10:25:42 +01002194 expected_video.total_inter_frame_delay = 0.123;
2195 expected_video.total_squared_inter_frame_delay = 0.00456;
Di Wu (RP Room Eng)8af6b492021-02-19 17:34:22 -08002196 expected_video.jitter = 1.199;
Byoungchan Lee899b29e2021-06-29 22:09:18 +09002197 expected_video.jitter_buffer_delay = 3.456;
2198 expected_video.jitter_buffer_emitted_count = 13;
Artem Titovcfea2182021-08-10 01:22:31 +02002199 // `expected_video.last_packet_received_timestamp` should be undefined.
2200 // `expected_video.content_type` should be undefined.
2201 // `expected_video.decoder_implementation` should be undefined.
hboseeafe942016-11-01 03:00:17 -07002202
nissec8ee8822017-01-18 07:20:55 -08002203 ASSERT_TRUE(report->Get(expected_video.id()));
hbosa51d4f32017-02-16 05:34:48 -08002204 EXPECT_EQ(
2205 report->Get(expected_video.id())->cast_to<RTCInboundRTPStreamStats>(),
2206 expected_video);
hboseeafe942016-11-01 03:00:17 -07002207
hbosa51d4f32017-02-16 05:34:48 -08002208 // Set previously undefined values and "GetStats" again.
Oskar Sundbomcbc71b22017-11-16 10:56:07 +01002209 video_media_info.receivers[0].qp_sum = 9;
hbosa51d4f32017-02-16 05:34:48 -08002210 expected_video.qp_sum = 9;
Åsa Perssonfcf79cc2019-10-22 15:23:44 +02002211 video_media_info.receivers[0].last_packet_received_timestamp_ms = 1000;
Alessio Bazzica5cf8c2c2021-03-24 08:51:26 +01002212 expected_video.last_packet_received_timestamp = 1000.0;
Henrik Boström2e069262019-04-09 13:59:31 +02002213 video_media_info.receivers[0].content_type = VideoContentType::SCREENSHARE;
2214 expected_video.content_type = "screenshare";
Åsa Perssonfcf79cc2019-10-22 15:23:44 +02002215 video_media_info.receivers[0].estimated_playout_ntp_timestamp_ms = 1234;
2216 expected_video.estimated_playout_timestamp = 1234;
Henrik Boström6b430862019-08-16 13:09:51 +02002217 video_media_info.receivers[0].decoder_implementation_name = "libfoodecoder";
2218 expected_video.decoder_implementation = "libfoodecoder";
Steve Anton5b387312018-02-02 16:00:20 -08002219 video_media_channel->SetStats(video_media_info);
hbosa51d4f32017-02-16 05:34:48 -08002220
Steve Anton5b387312018-02-02 16:00:20 -08002221 report = stats_->GetFreshStatsReport();
hbosa51d4f32017-02-16 05:34:48 -08002222
2223 ASSERT_TRUE(report->Get(expected_video.id()));
2224 EXPECT_EQ(
2225 report->Get(expected_video.id())->cast_to<RTCInboundRTPStreamStats>(),
2226 expected_video);
hbosb0ae9202017-01-27 06:35:16 -08002227 EXPECT_TRUE(report->Get(*expected_video.track_id));
hbos84abeb12017-01-16 06:16:44 -08002228 EXPECT_TRUE(report->Get(*expected_video.transport_id));
hbosa51d4f32017-02-16 05:34:48 -08002229 EXPECT_TRUE(report->Get(*expected_video.codec_id));
hboseeafe942016-11-01 03:00:17 -07002230}
2231
hbos6ded1902016-11-01 01:50:46 -07002232TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRTPStreamStats_Audio) {
hbos6ded1902016-11-01 01:50:46 -07002233 cricket::VoiceMediaInfo voice_media_info;
hbos0adb8282016-11-23 02:32:06 -08002234
hbos6ded1902016-11-01 01:50:46 -07002235 voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
2236 voice_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
2237 voice_media_info.senders[0].local_stats[0].ssrc = 1;
2238 voice_media_info.senders[0].packets_sent = 2;
Henrik Boströmcf96e0f2019-04-17 13:51:53 +02002239 voice_media_info.senders[0].retransmitted_packets_sent = 20;
Niels Möllerac0a4cb2019-10-09 15:01:33 +02002240 voice_media_info.senders[0].payload_bytes_sent = 3;
2241 voice_media_info.senders[0].header_and_padding_bytes_sent = 12;
Henrik Boströmcf96e0f2019-04-17 13:51:53 +02002242 voice_media_info.senders[0].retransmitted_bytes_sent = 30;
Jakob Ivarssone91c9922021-07-06 09:55:43 +02002243 voice_media_info.senders[0].nacks_rcvd = 31;
Jakob Ivarssonbf087452021-11-11 13:43:49 +01002244 voice_media_info.senders[0].target_bitrate = 32000;
Oskar Sundbomcbc71b22017-11-16 10:56:07 +01002245 voice_media_info.senders[0].codec_payload_type = 42;
hbos0adb8282016-11-23 02:32:06 -08002246
2247 RtpCodecParameters codec_parameters;
2248 codec_parameters.payload_type = 42;
deadbeefe702b302017-02-04 12:09:01 -08002249 codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
2250 codec_parameters.name = "dummy";
Oskar Sundbomcbc71b22017-11-16 10:56:07 +01002251 codec_parameters.clock_rate = 0;
hbos0adb8282016-11-23 02:32:06 -08002252 voice_media_info.send_codecs.insert(
2253 std::make_pair(codec_parameters.payload_type, codec_parameters));
2254
Tommi19015512022-02-02 11:49:35 +01002255 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Steve Anton5b387312018-02-02 16:00:20 -08002256 stats_->SetupLocalTrackAndSender(cricket::MEDIA_TYPE_AUDIO,
Henrik Boström646fda02019-05-22 15:49:42 +02002257 "LocalAudioTrackID", 1, true,
2258 /*attachment_id=*/50);
hbos6ded1902016-11-01 01:50:46 -07002259
Steve Anton5b387312018-02-02 16:00:20 -08002260 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos6ded1902016-11-01 01:50:46 -07002261
Yves Gerey665174f2018-06-19 15:03:05 +02002262 RTCOutboundRTPStreamStats expected_audio("RTCOutboundRTPAudioStream_1",
2263 report->timestamp_us());
Henrik Boström646fda02019-05-22 15:49:42 +02002264 expected_audio.media_source_id = "RTCAudioSource_50";
Artem Titovcfea2182021-08-10 01:22:31 +02002265 // `expected_audio.remote_id` should be undefined.
hbos3443bb72017-02-07 06:28:11 -08002266 expected_audio.ssrc = 1;
hbos6ded1902016-11-01 01:50:46 -07002267 expected_audio.media_type = "audio";
Philipp Hancke3bc01662018-08-28 14:55:03 +02002268 expected_audio.kind = "audio";
Niels Möllerafb246b2022-04-20 14:26:50 +02002269 expected_audio.track_id = IdForType<RTCMediaStreamTrackStats>(report.get());
Steve Anton57858b32018-02-15 15:19:50 -08002270 expected_audio.transport_id = "RTCTransport_TransportName_1";
2271 expected_audio.codec_id = "RTCCodec_AudioMid_Outbound_42";
hbos6ded1902016-11-01 01:50:46 -07002272 expected_audio.packets_sent = 2;
Henrik Boströmcf96e0f2019-04-17 13:51:53 +02002273 expected_audio.retransmitted_packets_sent = 20;
hbos6ded1902016-11-01 01:50:46 -07002274 expected_audio.bytes_sent = 3;
Niels Möllerac0a4cb2019-10-09 15:01:33 +02002275 expected_audio.header_bytes_sent = 12;
Henrik Boströmcf96e0f2019-04-17 13:51:53 +02002276 expected_audio.retransmitted_bytes_sent = 30;
Jakob Ivarssone91c9922021-07-06 09:55:43 +02002277 expected_audio.nack_count = 31;
Jakob Ivarssonbf087452021-11-11 13:43:49 +01002278 expected_audio.target_bitrate = 32000;
hboscd195be2017-02-07 08:31:27 -08002279
hboscd195be2017-02-07 08:31:27 -08002280 ASSERT_TRUE(report->Get(expected_audio.id()));
hbosa51d4f32017-02-16 05:34:48 -08002281 EXPECT_EQ(
2282 report->Get(expected_audio.id())->cast_to<RTCOutboundRTPStreamStats>(),
2283 expected_audio);
skvladed02c6d2017-02-07 10:45:31 -08002284
hbosa51d4f32017-02-16 05:34:48 -08002285 ASSERT_TRUE(report->Get(expected_audio.id()));
2286 EXPECT_EQ(
2287 report->Get(expected_audio.id())->cast_to<RTCOutboundRTPStreamStats>(),
2288 expected_audio);
hbosb0ae9202017-01-27 06:35:16 -08002289 EXPECT_TRUE(report->Get(*expected_audio.track_id));
hbos84abeb12017-01-16 06:16:44 -08002290 EXPECT_TRUE(report->Get(*expected_audio.transport_id));
2291 EXPECT_TRUE(report->Get(*expected_audio.codec_id));
hbos6ded1902016-11-01 01:50:46 -07002292}
2293
2294TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRTPStreamStats_Video) {
hbos6ded1902016-11-01 01:50:46 -07002295 cricket::VideoMediaInfo video_media_info;
hbos0adb8282016-11-23 02:32:06 -08002296
hbos6ded1902016-11-01 01:50:46 -07002297 video_media_info.senders.push_back(cricket::VideoSenderInfo());
2298 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
2299 video_media_info.senders[0].local_stats[0].ssrc = 1;
2300 video_media_info.senders[0].firs_rcvd = 2;
2301 video_media_info.senders[0].plis_rcvd = 3;
2302 video_media_info.senders[0].nacks_rcvd = 4;
2303 video_media_info.senders[0].packets_sent = 5;
Henrik Boströmcf96e0f2019-04-17 13:51:53 +02002304 video_media_info.senders[0].retransmitted_packets_sent = 50;
Niels Möllerac0a4cb2019-10-09 15:01:33 +02002305 video_media_info.senders[0].payload_bytes_sent = 6;
2306 video_media_info.senders[0].header_and_padding_bytes_sent = 12;
Henrik Boströmcf96e0f2019-04-17 13:51:53 +02002307 video_media_info.senders[0].retransmitted_bytes_sent = 60;
Oskar Sundbomcbc71b22017-11-16 10:56:07 +01002308 video_media_info.senders[0].codec_payload_type = 42;
hbos6769c492017-01-02 08:35:13 -08002309 video_media_info.senders[0].frames_encoded = 8;
Rasmus Brandt2efae772019-06-27 14:29:34 +02002310 video_media_info.senders[0].key_frames_encoded = 3;
Henrik Boströmf71362f2019-04-08 16:14:23 +02002311 video_media_info.senders[0].total_encode_time_ms = 9000;
Henrik Boström23aff9b2019-05-20 15:15:38 +02002312 video_media_info.senders[0].total_encoded_bytes_target = 1234;
Henrik Boström9fe18342019-05-16 18:38:20 +02002313 video_media_info.senders[0].total_packet_send_delay_ms = 10000;
Henrik Boströmce33b6a2019-05-28 17:42:38 +02002314 video_media_info.senders[0].quality_limitation_reason =
2315 QualityLimitationReason::kBandwidth;
Byoungchan Lee7d235352021-05-28 21:32:04 +09002316 video_media_info.senders[0].quality_limitation_durations_ms
2317 [webrtc::QualityLimitationReason::kBandwidth] = 300;
Evan Shrubsolecc62b162019-09-09 11:26:45 +02002318 video_media_info.senders[0].quality_limitation_resolution_changes = 56u;
Danil Chapovalov66cadcc2018-06-19 16:47:43 +02002319 video_media_info.senders[0].qp_sum = absl::nullopt;
Henrik Boström2e069262019-04-09 13:59:31 +02002320 video_media_info.senders[0].content_type = VideoContentType::UNSPECIFIED;
Henrik Boström6b430862019-08-16 13:09:51 +02002321 video_media_info.senders[0].encoder_implementation_name = "";
Henrik Boströma0ff50c2020-05-05 15:54:46 +02002322 video_media_info.senders[0].send_frame_width = 200;
2323 video_media_info.senders[0].send_frame_height = 100;
2324 video_media_info.senders[0].framerate_sent = 10;
2325 video_media_info.senders[0].frames_sent = 5;
2326 video_media_info.senders[0].huge_frames_sent = 2;
2327 video_media_info.aggregated_senders.push_back(video_media_info.senders[0]);
hbos0adb8282016-11-23 02:32:06 -08002328 RtpCodecParameters codec_parameters;
2329 codec_parameters.payload_type = 42;
deadbeefe702b302017-02-04 12:09:01 -08002330 codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
2331 codec_parameters.name = "dummy";
Oskar Sundbomcbc71b22017-11-16 10:56:07 +01002332 codec_parameters.clock_rate = 0;
hbos0adb8282016-11-23 02:32:06 -08002333 video_media_info.send_codecs.insert(
2334 std::make_pair(codec_parameters.payload_type, codec_parameters));
2335
Tommi19015512022-02-02 11:49:35 +01002336 auto* video_media_channel =
2337 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Steve Anton5b387312018-02-02 16:00:20 -08002338 stats_->SetupLocalTrackAndSender(cricket::MEDIA_TYPE_VIDEO,
Henrik Boström646fda02019-05-22 15:49:42 +02002339 "LocalVideoTrackID", 1, true,
2340 /*attachment_id=*/50);
hbos6ded1902016-11-01 01:50:46 -07002341
Steve Anton5b387312018-02-02 16:00:20 -08002342 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos6ded1902016-11-01 01:50:46 -07002343
Harald Alvestranda3dab842018-01-14 09:18:58 +01002344 auto stats_of_my_type = report->GetStatsOfType<RTCOutboundRTPStreamStats>();
Mirko Bonadeie12c1fe2018-07-03 12:53:23 +02002345 ASSERT_EQ(1U, stats_of_my_type.size());
Harald Alvestranda3dab842018-01-14 09:18:58 +01002346 auto stats_of_track_type = report->GetStatsOfType<RTCMediaStreamTrackStats>();
Mirko Bonadeie12c1fe2018-07-03 12:53:23 +02002347 ASSERT_EQ(1U, stats_of_track_type.size());
Harald Alvestranda3dab842018-01-14 09:18:58 +01002348
2349 RTCOutboundRTPStreamStats expected_video(stats_of_my_type[0]->id(),
2350 report->timestamp_us());
Henrik Boström646fda02019-05-22 15:49:42 +02002351 expected_video.media_source_id = "RTCVideoSource_50";
Artem Titovcfea2182021-08-10 01:22:31 +02002352 // `expected_video.remote_id` should be undefined.
hbos3443bb72017-02-07 06:28:11 -08002353 expected_video.ssrc = 1;
hbos6ded1902016-11-01 01:50:46 -07002354 expected_video.media_type = "video";
Philipp Hancke3bc01662018-08-28 14:55:03 +02002355 expected_video.kind = "video";
Harald Alvestranda3dab842018-01-14 09:18:58 +01002356 expected_video.track_id = stats_of_track_type[0]->id();
Steve Anton57858b32018-02-15 15:19:50 -08002357 expected_video.transport_id = "RTCTransport_TransportName_1";
2358 expected_video.codec_id = "RTCCodec_VideoMid_Outbound_42";
hbos6ded1902016-11-01 01:50:46 -07002359 expected_video.fir_count = 2;
2360 expected_video.pli_count = 3;
2361 expected_video.nack_count = 4;
2362 expected_video.packets_sent = 5;
Henrik Boströmcf96e0f2019-04-17 13:51:53 +02002363 expected_video.retransmitted_packets_sent = 50;
hbos6ded1902016-11-01 01:50:46 -07002364 expected_video.bytes_sent = 6;
Niels Möllerac0a4cb2019-10-09 15:01:33 +02002365 expected_video.header_bytes_sent = 12;
Henrik Boströmcf96e0f2019-04-17 13:51:53 +02002366 expected_video.retransmitted_bytes_sent = 60;
skvladed02c6d2017-02-07 10:45:31 -08002367 expected_video.frames_encoded = 8;
Rasmus Brandt2efae772019-06-27 14:29:34 +02002368 expected_video.key_frames_encoded = 3;
Henrik Boströmf71362f2019-04-08 16:14:23 +02002369 expected_video.total_encode_time = 9.0;
Henrik Boström23aff9b2019-05-20 15:15:38 +02002370 expected_video.total_encoded_bytes_target = 1234;
Henrik Boström9fe18342019-05-16 18:38:20 +02002371 expected_video.total_packet_send_delay = 10.0;
Henrik Boströmce33b6a2019-05-28 17:42:38 +02002372 expected_video.quality_limitation_reason = "bandwidth";
Byoungchan Lee7d235352021-05-28 21:32:04 +09002373 expected_video.quality_limitation_durations = std::map<std::string, double>{
Philipp Hancke3fd9cbc2022-01-10 17:41:43 +01002374 std::pair<std::string, double>{"bandwidth", 0.3},
Byoungchan Lee7d235352021-05-28 21:32:04 +09002375 };
Evan Shrubsolecc62b162019-09-09 11:26:45 +02002376 expected_video.quality_limitation_resolution_changes = 56u;
Eldar Rello9276e2c2020-06-10 17:53:39 +03002377 expected_video.frame_width = 200u;
2378 expected_video.frame_height = 100u;
2379 expected_video.frames_per_second = 10.0;
2380 expected_video.frames_sent = 5;
2381 expected_video.huge_frames_sent = 2;
Artem Titovcfea2182021-08-10 01:22:31 +02002382 // `expected_video.content_type` should be undefined.
2383 // `expected_video.qp_sum` should be undefined.
2384 // `expected_video.encoder_implementation` should be undefined.
hboscd195be2017-02-07 08:31:27 -08002385 ASSERT_TRUE(report->Get(expected_video.id()));
Harald Alvestranda3dab842018-01-14 09:18:58 +01002386
hbosa51d4f32017-02-16 05:34:48 -08002387 EXPECT_EQ(
2388 report->Get(expected_video.id())->cast_to<RTCOutboundRTPStreamStats>(),
2389 expected_video);
skvladed02c6d2017-02-07 10:45:31 -08002390
hbosa51d4f32017-02-16 05:34:48 -08002391 // Set previously undefined values and "GetStats" again.
Oskar Sundbomcbc71b22017-11-16 10:56:07 +01002392 video_media_info.senders[0].qp_sum = 9;
hbosa51d4f32017-02-16 05:34:48 -08002393 expected_video.qp_sum = 9;
Henrik Boström2e069262019-04-09 13:59:31 +02002394 video_media_info.senders[0].content_type = VideoContentType::SCREENSHARE;
2395 expected_video.content_type = "screenshare";
Henrik Boström6b430862019-08-16 13:09:51 +02002396 video_media_info.senders[0].encoder_implementation_name = "libfooencoder";
Henrik Boströma0ff50c2020-05-05 15:54:46 +02002397 video_media_info.aggregated_senders[0] = video_media_info.senders[0];
Henrik Boström6b430862019-08-16 13:09:51 +02002398 expected_video.encoder_implementation = "libfooencoder";
Steve Anton5b387312018-02-02 16:00:20 -08002399 video_media_channel->SetStats(video_media_info);
hbosa51d4f32017-02-16 05:34:48 -08002400
Steve Anton5b387312018-02-02 16:00:20 -08002401 report = stats_->GetFreshStatsReport();
hbosa51d4f32017-02-16 05:34:48 -08002402
2403 ASSERT_TRUE(report->Get(expected_video.id()));
2404 EXPECT_EQ(
2405 report->Get(expected_video.id())->cast_to<RTCOutboundRTPStreamStats>(),
2406 expected_video);
hbosb0ae9202017-01-27 06:35:16 -08002407 EXPECT_TRUE(report->Get(*expected_video.track_id));
hbos84abeb12017-01-16 06:16:44 -08002408 EXPECT_TRUE(report->Get(*expected_video.transport_id));
2409 EXPECT_TRUE(report->Get(*expected_video.codec_id));
hbos6ded1902016-11-01 01:50:46 -07002410}
2411
hbos2fa7c672016-10-24 04:00:05 -07002412TEST_F(RTCStatsCollectorTest, CollectRTCTransportStats) {
Steve Anton5b387312018-02-02 16:00:20 -08002413 const char kTransportName[] = "transport";
2414
2415 pc_->AddVoiceChannel("audio", kTransportName);
2416
Gary Liu37e489c2017-11-21 10:49:36 -08002417 std::unique_ptr<cricket::Candidate> rtp_local_candidate =
2418 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
2419 cricket::LOCAL_PORT_TYPE, 42);
hbos2fa7c672016-10-24 04:00:05 -07002420 std::unique_ptr<cricket::Candidate> rtp_remote_candidate =
2421 CreateFakeCandidate("42.42.42.42", 42, "protocol",
Gary Liu37e489c2017-11-21 10:49:36 -08002422 rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
2423 42);
hbos2fa7c672016-10-24 04:00:05 -07002424 std::unique_ptr<cricket::Candidate> rtcp_local_candidate =
Gary Liu37e489c2017-11-21 10:49:36 -08002425 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
hbos2fa7c672016-10-24 04:00:05 -07002426 cricket::LOCAL_PORT_TYPE, 42);
2427 std::unique_ptr<cricket::Candidate> rtcp_remote_candidate =
2428 CreateFakeCandidate("42.42.42.42", 42, "protocol",
Gary Liu37e489c2017-11-21 10:49:36 -08002429 rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
2430 42);
hbos2fa7c672016-10-24 04:00:05 -07002431
hbos2fa7c672016-10-24 04:00:05 -07002432 cricket::ConnectionInfo rtp_connection_info;
2433 rtp_connection_info.best_connection = false;
2434 rtp_connection_info.local_candidate = *rtp_local_candidate.get();
2435 rtp_connection_info.remote_candidate = *rtp_remote_candidate.get();
2436 rtp_connection_info.sent_total_bytes = 42;
2437 rtp_connection_info.recv_total_bytes = 1337;
Artem Titovedacbd52020-07-06 16:06:37 +02002438 rtp_connection_info.sent_total_packets = 3;
2439 rtp_connection_info.sent_discarded_packets = 2;
2440 rtp_connection_info.packets_received = 4;
hbos2fa7c672016-10-24 04:00:05 -07002441 cricket::TransportChannelStats rtp_transport_channel_stats;
2442 rtp_transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
Jonas Oreland149dc722019-08-28 08:10:27 +02002443 rtp_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
2444 rtp_connection_info);
Mirko Bonadei9f6808b2021-05-21 20:46:09 +02002445 rtp_transport_channel_stats.dtls_state = DtlsTransportState::kNew;
Jonas Oreland42da5a92022-03-01 13:55:37 +01002446 rtp_transport_channel_stats.ice_transport_stats.bytes_sent = 42;
2447 rtp_transport_channel_stats.ice_transport_stats.packets_sent = 1;
2448 rtp_transport_channel_stats.ice_transport_stats.bytes_received = 1337;
2449 rtp_transport_channel_stats.ice_transport_stats.packets_received = 4;
Jonas Oreland149dc722019-08-28 08:10:27 +02002450 rtp_transport_channel_stats.ice_transport_stats
2451 .selected_candidate_pair_changes = 1;
Philipp Hancke95b1a342022-05-05 07:53:54 +02002452 rtp_transport_channel_stats.ice_transport_stats.ice_local_username_fragment =
2453 "thelocalufrag";
Steve Anton5b387312018-02-02 16:00:20 -08002454 pc_->SetTransportStats(kTransportName, {rtp_transport_channel_stats});
hbos2fa7c672016-10-24 04:00:05 -07002455
2456 // Get stats without RTCP, an active connection or certificates.
Steve Anton5b387312018-02-02 16:00:20 -08002457 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
hbos0583b282016-11-30 01:50:14 -08002458
2459 RTCTransportStats expected_rtp_transport(
2460 "RTCTransport_transport_" +
Jonas Olsson6b1985d2018-07-05 11:59:48 +02002461 rtc::ToString(cricket::ICE_CANDIDATE_COMPONENT_RTP),
hbos0583b282016-11-30 01:50:14 -08002462 report->timestamp_us());
2463 expected_rtp_transport.bytes_sent = 42;
Artem Titovedacbd52020-07-06 16:06:37 +02002464 expected_rtp_transport.packets_sent = 1;
hbos0583b282016-11-30 01:50:14 -08002465 expected_rtp_transport.bytes_received = 1337;
Artem Titovedacbd52020-07-06 16:06:37 +02002466 expected_rtp_transport.packets_received = 4;
hbos7064d592017-01-16 07:38:02 -08002467 expected_rtp_transport.dtls_state = RTCDtlsTransportState::kNew;
Philipp Hancke69c1df22022-04-22 15:46:24 +02002468 expected_rtp_transport.dtls_role = RTCDtlsRole::kUnknown;
Jonas Oreland149dc722019-08-28 08:10:27 +02002469 expected_rtp_transport.selected_candidate_pair_changes = 1;
Philipp Hanckecc1b9b02022-05-04 18:58:26 +02002470 expected_rtp_transport.ice_role = RTCIceRole::kUnknown;
Philipp Hancke95b1a342022-05-05 07:53:54 +02002471 expected_rtp_transport.ice_local_username_fragment = "thelocalufrag";
hbos0583b282016-11-30 01:50:14 -08002472
hbosdbb64d82016-12-21 01:57:46 -08002473 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
hbos0583b282016-11-30 01:50:14 -08002474 EXPECT_EQ(
2475 expected_rtp_transport,
2476 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
hbos2fa7c672016-10-24 04:00:05 -07002477
2478 cricket::ConnectionInfo rtcp_connection_info;
2479 rtcp_connection_info.best_connection = false;
2480 rtcp_connection_info.local_candidate = *rtcp_local_candidate.get();
2481 rtcp_connection_info.remote_candidate = *rtcp_remote_candidate.get();
2482 rtcp_connection_info.sent_total_bytes = 1337;
2483 rtcp_connection_info.recv_total_bytes = 42;
Artem Titovedacbd52020-07-06 16:06:37 +02002484 rtcp_connection_info.sent_total_packets = 3;
2485 rtcp_connection_info.sent_discarded_packets = 2;
2486 rtcp_connection_info.packets_received = 4;
hbos2fa7c672016-10-24 04:00:05 -07002487 cricket::TransportChannelStats rtcp_transport_channel_stats;
2488 rtcp_transport_channel_stats.component =
2489 cricket::ICE_CANDIDATE_COMPONENT_RTCP;
Jonas Oreland149dc722019-08-28 08:10:27 +02002490 rtcp_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
2491 rtcp_connection_info);
Mirko Bonadei9f6808b2021-05-21 20:46:09 +02002492 rtcp_transport_channel_stats.dtls_state = DtlsTransportState::kConnecting;
Jonas Oreland42da5a92022-03-01 13:55:37 +01002493 rtcp_transport_channel_stats.ice_transport_stats.bytes_sent = 1337;
2494 rtcp_transport_channel_stats.ice_transport_stats.packets_sent = 1;
2495 rtcp_transport_channel_stats.ice_transport_stats.bytes_received = 42;
2496 rtcp_transport_channel_stats.ice_transport_stats.packets_received = 4;
Philipp Hancke95b1a342022-05-05 07:53:54 +02002497 rtcp_transport_channel_stats.ice_transport_stats.ice_local_username_fragment =
2498 "thelocalufrag";
Steve Anton5b387312018-02-02 16:00:20 -08002499 pc_->SetTransportStats(kTransportName, {rtp_transport_channel_stats,
2500 rtcp_transport_channel_stats});
hbos2fa7c672016-10-24 04:00:05 -07002501
hbos2fa7c672016-10-24 04:00:05 -07002502 // Get stats with RTCP and without an active connection or certificates.
Steve Anton5b387312018-02-02 16:00:20 -08002503 report = stats_->GetFreshStatsReport();
hbos0583b282016-11-30 01:50:14 -08002504
2505 RTCTransportStats expected_rtcp_transport(
2506 "RTCTransport_transport_" +
Jonas Olsson6b1985d2018-07-05 11:59:48 +02002507 rtc::ToString(cricket::ICE_CANDIDATE_COMPONENT_RTCP),
hbos0583b282016-11-30 01:50:14 -08002508 report->timestamp_us());
2509 expected_rtcp_transport.bytes_sent = 1337;
Artem Titovedacbd52020-07-06 16:06:37 +02002510 expected_rtcp_transport.packets_sent = 1;
hbos0583b282016-11-30 01:50:14 -08002511 expected_rtcp_transport.bytes_received = 42;
Artem Titovedacbd52020-07-06 16:06:37 +02002512 expected_rtcp_transport.packets_received = 4;
hbos7064d592017-01-16 07:38:02 -08002513 expected_rtcp_transport.dtls_state = RTCDtlsTransportState::kConnecting;
Philipp Hancke69c1df22022-04-22 15:46:24 +02002514 expected_rtcp_transport.dtls_role = RTCDtlsRole::kUnknown;
Jonas Oreland149dc722019-08-28 08:10:27 +02002515 expected_rtcp_transport.selected_candidate_pair_changes = 0;
Philipp Hanckecc1b9b02022-05-04 18:58:26 +02002516 expected_rtcp_transport.ice_role = RTCIceRole::kUnknown;
Philipp Hancke95b1a342022-05-05 07:53:54 +02002517 expected_rtcp_transport.ice_local_username_fragment = "thelocalufrag";
hbos0583b282016-11-30 01:50:14 -08002518
2519 expected_rtp_transport.rtcp_transport_stats_id = expected_rtcp_transport.id();
hbosdbb64d82016-12-21 01:57:46 -08002520 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
hbos0583b282016-11-30 01:50:14 -08002521 EXPECT_EQ(
2522 expected_rtp_transport,
2523 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
hbosdbb64d82016-12-21 01:57:46 -08002524 ASSERT_TRUE(report->Get(expected_rtcp_transport.id()));
hbos0583b282016-11-30 01:50:14 -08002525 EXPECT_EQ(
2526 expected_rtcp_transport,
2527 report->Get(expected_rtcp_transport.id())->cast_to<RTCTransportStats>());
hbos2fa7c672016-10-24 04:00:05 -07002528
hbos7064d592017-01-16 07:38:02 -08002529 // Get stats with an active connection (selected candidate pair).
Jonas Oreland149dc722019-08-28 08:10:27 +02002530 rtcp_transport_channel_stats.ice_transport_stats.connection_infos[0]
2531 .best_connection = true;
Steve Anton5b387312018-02-02 16:00:20 -08002532 pc_->SetTransportStats(kTransportName, {rtp_transport_channel_stats,
2533 rtcp_transport_channel_stats});
hbos2fa7c672016-10-24 04:00:05 -07002534
Steve Anton5b387312018-02-02 16:00:20 -08002535 report = stats_->GetFreshStatsReport();
hbos0583b282016-11-30 01:50:14 -08002536
hbos0583b282016-11-30 01:50:14 -08002537 expected_rtcp_transport.selected_candidate_pair_id =
2538 "RTCIceCandidatePair_" + rtcp_local_candidate->id() + "_" +
2539 rtcp_remote_candidate->id();
2540
hbosdbb64d82016-12-21 01:57:46 -08002541 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
hbos0583b282016-11-30 01:50:14 -08002542 EXPECT_EQ(
2543 expected_rtp_transport,
2544 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
hbosdbb64d82016-12-21 01:57:46 -08002545 ASSERT_TRUE(report->Get(expected_rtcp_transport.id()));
hbos0583b282016-11-30 01:50:14 -08002546 EXPECT_EQ(
2547 expected_rtcp_transport,
2548 report->Get(expected_rtcp_transport.id())->cast_to<RTCTransportStats>());
hbos2fa7c672016-10-24 04:00:05 -07002549
2550 // Get stats with certificates.
2551 std::unique_ptr<CertificateInfo> local_certinfo =
Steve Anton5b387312018-02-02 16:00:20 -08002552 CreateFakeCertificateAndInfoFromDers({"(local) local", "(local) chain"});
2553 pc_->SetLocalCertificate(kTransportName, local_certinfo->certificate);
hbos2fa7c672016-10-24 04:00:05 -07002554 std::unique_ptr<CertificateInfo> remote_certinfo =
2555 CreateFakeCertificateAndInfoFromDers(
Steve Anton5b387312018-02-02 16:00:20 -08002556 {"(remote) local", "(remote) chain"});
Taylor Brandstetterc3928662018-02-23 13:04:51 -08002557 pc_->SetRemoteCertChain(
Benjamin Wright6c6c9df2018-10-25 01:16:26 -07002558 kTransportName,
2559 remote_certinfo->certificate->GetSSLCertificateChain().Clone());
hbos2fa7c672016-10-24 04:00:05 -07002560
Steve Anton5b387312018-02-02 16:00:20 -08002561 report = stats_->GetFreshStatsReport();
hbos0583b282016-11-30 01:50:14 -08002562
2563 expected_rtp_transport.local_certificate_id =
2564 "RTCCertificate_" + local_certinfo->fingerprints[0];
2565 expected_rtp_transport.remote_certificate_id =
2566 "RTCCertificate_" + remote_certinfo->fingerprints[0];
2567
2568 expected_rtcp_transport.local_certificate_id =
2569 *expected_rtp_transport.local_certificate_id;
2570 expected_rtcp_transport.remote_certificate_id =
2571 *expected_rtp_transport.remote_certificate_id;
2572
hbosdbb64d82016-12-21 01:57:46 -08002573 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
hbos0583b282016-11-30 01:50:14 -08002574 EXPECT_EQ(
2575 expected_rtp_transport,
2576 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
hbosdbb64d82016-12-21 01:57:46 -08002577 ASSERT_TRUE(report->Get(expected_rtcp_transport.id()));
hbos0583b282016-11-30 01:50:14 -08002578 EXPECT_EQ(
2579 expected_rtcp_transport,
2580 report->Get(expected_rtcp_transport.id())->cast_to<RTCTransportStats>());
hbos2fa7c672016-10-24 04:00:05 -07002581}
2582
Harald Alvestrand5cb78072019-10-28 09:51:17 +01002583TEST_F(RTCStatsCollectorTest, CollectRTCTransportStatsWithCrypto) {
2584 const char kTransportName[] = "transport";
2585
2586 pc_->AddVoiceChannel("audio", kTransportName);
2587
2588 std::unique_ptr<cricket::Candidate> rtp_local_candidate =
2589 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
2590 cricket::LOCAL_PORT_TYPE, 42);
2591 std::unique_ptr<cricket::Candidate> rtp_remote_candidate =
2592 CreateFakeCandidate("42.42.42.42", 42, "protocol",
2593 rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
2594 42);
2595 std::unique_ptr<cricket::Candidate> rtcp_local_candidate =
2596 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
2597 cricket::LOCAL_PORT_TYPE, 42);
2598 std::unique_ptr<cricket::Candidate> rtcp_remote_candidate =
2599 CreateFakeCandidate("42.42.42.42", 42, "protocol",
2600 rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
2601 42);
2602
2603 cricket::ConnectionInfo rtp_connection_info;
2604 rtp_connection_info.best_connection = false;
2605 rtp_connection_info.local_candidate = *rtp_local_candidate.get();
2606 rtp_connection_info.remote_candidate = *rtp_remote_candidate.get();
Harald Alvestrand5cb78072019-10-28 09:51:17 +01002607 cricket::TransportChannelStats rtp_transport_channel_stats;
2608 rtp_transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
2609 rtp_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
2610 rtp_connection_info);
2611 // The state must be connected in order for crypto parameters to show up.
Mirko Bonadei9f6808b2021-05-21 20:46:09 +02002612 rtp_transport_channel_stats.dtls_state = DtlsTransportState::kConnected;
Harald Alvestrand5cb78072019-10-28 09:51:17 +01002613 rtp_transport_channel_stats.ice_transport_stats
2614 .selected_candidate_pair_changes = 1;
2615 rtp_transport_channel_stats.ssl_version_bytes = 0x0203;
Philipp Hancke69c1df22022-04-22 15:46:24 +02002616 rtp_transport_channel_stats.dtls_role = rtc::SSL_CLIENT;
Philipp Hanckecc1b9b02022-05-04 18:58:26 +02002617 rtp_transport_channel_stats.ice_transport_stats.ice_role =
2618 cricket::ICEROLE_CONTROLLING;
Philipp Hancke95b1a342022-05-05 07:53:54 +02002619 rtp_transport_channel_stats.ice_transport_stats.ice_local_username_fragment =
2620 "thelocalufrag";
Harald Alvestrand5cb78072019-10-28 09:51:17 +01002621 // 0x2F is TLS_RSA_WITH_AES_128_CBC_SHA according to IANA
2622 rtp_transport_channel_stats.ssl_cipher_suite = 0x2F;
Mirko Bonadei7750d802021-07-26 17:27:42 +02002623 rtp_transport_channel_stats.srtp_crypto_suite = rtc::kSrtpAes128CmSha1_80;
Harald Alvestrand5cb78072019-10-28 09:51:17 +01002624 pc_->SetTransportStats(kTransportName, {rtp_transport_channel_stats});
2625
2626 // Get stats
2627 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
2628
2629 RTCTransportStats expected_rtp_transport(
2630 "RTCTransport_transport_" +
2631 rtc::ToString(cricket::ICE_CANDIDATE_COMPONENT_RTP),
2632 report->timestamp_us());
Harald Alvestrand5cb78072019-10-28 09:51:17 +01002633 expected_rtp_transport.dtls_state = RTCDtlsTransportState::kConnected;
2634 expected_rtp_transport.selected_candidate_pair_changes = 1;
Philipp Hanckecc1b9b02022-05-04 18:58:26 +02002635 expected_rtp_transport.ice_role = RTCIceRole::kUnknown;
Jonas Oreland42da5a92022-03-01 13:55:37 +01002636 expected_rtp_transport.bytes_sent = 0;
2637 expected_rtp_transport.bytes_received = 0;
2638 expected_rtp_transport.packets_sent = 0;
2639 expected_rtp_transport.packets_received = 0;
Philipp Hancke95b1a342022-05-05 07:53:54 +02002640 expected_rtp_transport.ice_role = RTCIceRole::kControlling;
2641 expected_rtp_transport.ice_local_username_fragment = "thelocalufrag";
Harald Alvestrand5cb78072019-10-28 09:51:17 +01002642 // Crypto parameters
2643 expected_rtp_transport.tls_version = "0203";
Philipp Hancke69c1df22022-04-22 15:46:24 +02002644 expected_rtp_transport.dtls_role = RTCDtlsRole::kClient;
Harald Alvestrand5cb78072019-10-28 09:51:17 +01002645 expected_rtp_transport.dtls_cipher = "TLS_RSA_WITH_AES_128_CBC_SHA";
2646 expected_rtp_transport.srtp_cipher = "AES_CM_128_HMAC_SHA1_80";
2647
2648 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
2649 EXPECT_EQ(
2650 expected_rtp_transport,
2651 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
2652}
2653
Harald Alvestrand89061872018-01-02 14:08:34 +01002654TEST_F(RTCStatsCollectorTest, CollectNoStreamRTCOutboundRTPStreamStats_Audio) {
Harald Alvestrand89061872018-01-02 14:08:34 +01002655 cricket::VoiceMediaInfo voice_media_info;
2656
2657 voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
2658 voice_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
2659 voice_media_info.senders[0].local_stats[0].ssrc = 1;
2660 voice_media_info.senders[0].packets_sent = 2;
Henrik Boströmcf96e0f2019-04-17 13:51:53 +02002661 voice_media_info.senders[0].retransmitted_packets_sent = 20;
Niels Möllerac0a4cb2019-10-09 15:01:33 +02002662 voice_media_info.senders[0].payload_bytes_sent = 3;
2663 voice_media_info.senders[0].header_and_padding_bytes_sent = 4;
Henrik Boströmcf96e0f2019-04-17 13:51:53 +02002664 voice_media_info.senders[0].retransmitted_bytes_sent = 30;
Jakob Ivarssone91c9922021-07-06 09:55:43 +02002665 voice_media_info.senders[0].nacks_rcvd = 31;
Harald Alvestrand89061872018-01-02 14:08:34 +01002666 voice_media_info.senders[0].codec_payload_type = 42;
2667
2668 RtpCodecParameters codec_parameters;
2669 codec_parameters.payload_type = 42;
2670 codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
2671 codec_parameters.name = "dummy";
2672 codec_parameters.clock_rate = 0;
2673 voice_media_info.send_codecs.insert(
2674 std::make_pair(codec_parameters.payload_type, codec_parameters));
2675
Steve Anton5b387312018-02-02 16:00:20 -08002676 // Emulates the case where AddTrack is used without an associated MediaStream
Tommi19015512022-02-02 11:49:35 +01002677 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Steve Anton5b387312018-02-02 16:00:20 -08002678 stats_->SetupLocalTrackAndSender(cricket::MEDIA_TYPE_AUDIO,
Henrik Boström646fda02019-05-22 15:49:42 +02002679 "LocalAudioTrackID", 1, false,
2680 /*attachment_id=*/50);
Harald Alvestrand89061872018-01-02 14:08:34 +01002681
Steve Anton5b387312018-02-02 16:00:20 -08002682 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Harald Alvestrand89061872018-01-02 14:08:34 +01002683
2684 RTCOutboundRTPStreamStats expected_audio("RTCOutboundRTPAudioStream_1",
2685 report->timestamp_us());
Henrik Boström646fda02019-05-22 15:49:42 +02002686 expected_audio.media_source_id = "RTCAudioSource_50";
Harald Alvestrand89061872018-01-02 14:08:34 +01002687 expected_audio.ssrc = 1;
Harald Alvestrand89061872018-01-02 14:08:34 +01002688 expected_audio.media_type = "audio";
Philipp Hancke3bc01662018-08-28 14:55:03 +02002689 expected_audio.kind = "audio";
Niels Möllerafb246b2022-04-20 14:26:50 +02002690 expected_audio.track_id = IdForType<RTCMediaStreamTrackStats>(report.get());
Steve Anton57858b32018-02-15 15:19:50 -08002691 expected_audio.transport_id = "RTCTransport_TransportName_1";
2692 expected_audio.codec_id = "RTCCodec_AudioMid_Outbound_42";
Harald Alvestrand89061872018-01-02 14:08:34 +01002693 expected_audio.packets_sent = 2;
Henrik Boströmcf96e0f2019-04-17 13:51:53 +02002694 expected_audio.retransmitted_packets_sent = 20;
Harald Alvestrand89061872018-01-02 14:08:34 +01002695 expected_audio.bytes_sent = 3;
Niels Möllerac0a4cb2019-10-09 15:01:33 +02002696 expected_audio.header_bytes_sent = 4;
Henrik Boströmcf96e0f2019-04-17 13:51:53 +02002697 expected_audio.retransmitted_bytes_sent = 30;
Jakob Ivarssone91c9922021-07-06 09:55:43 +02002698 expected_audio.nack_count = 31;
Harald Alvestrand89061872018-01-02 14:08:34 +01002699
2700 ASSERT_TRUE(report->Get(expected_audio.id()));
2701 EXPECT_EQ(
2702 report->Get(expected_audio.id())->cast_to<RTCOutboundRTPStreamStats>(),
2703 expected_audio);
Harald Alvestrand89061872018-01-02 14:08:34 +01002704 EXPECT_TRUE(report->Get(*expected_audio.track_id));
2705 EXPECT_TRUE(report->Get(*expected_audio.transport_id));
2706 EXPECT_TRUE(report->Get(*expected_audio.codec_id));
2707}
2708
Henrik Boström646fda02019-05-22 15:49:42 +02002709TEST_F(RTCStatsCollectorTest, RTCAudioSourceStatsCollectedForSenderWithTrack) {
2710 const uint32_t kSsrc = 4;
2711 const int kAttachmentId = 42;
2712
2713 cricket::VoiceMediaInfo voice_media_info;
2714 voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
2715 voice_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
2716 voice_media_info.senders[0].local_stats[0].ssrc = kSsrc;
Henrik Boströmd2c336f2019-07-03 17:11:10 +02002717 voice_media_info.senders[0].audio_level = 32767; // [0,32767]
2718 voice_media_info.senders[0].total_input_energy = 2.0;
2719 voice_media_info.senders[0].total_input_duration = 3.0;
Taylor Brandstetter64851c02021-06-24 13:32:50 -07002720 voice_media_info.senders[0].apm_statistics.echo_return_loss = 42.0;
2721 voice_media_info.senders[0].apm_statistics.echo_return_loss_enhancement =
2722 52.0;
Tommi19015512022-02-02 11:49:35 +01002723 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Henrik Boström646fda02019-05-22 15:49:42 +02002724 stats_->SetupLocalTrackAndSender(cricket::MEDIA_TYPE_AUDIO,
2725 "LocalAudioTrackID", kSsrc, false,
2726 kAttachmentId);
2727
2728 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
2729
2730 RTCAudioSourceStats expected_audio("RTCAudioSource_42",
2731 report->timestamp_us());
2732 expected_audio.track_identifier = "LocalAudioTrackID";
2733 expected_audio.kind = "audio";
Henrik Boströmd2c336f2019-07-03 17:11:10 +02002734 expected_audio.audio_level = 1.0; // [0,1]
2735 expected_audio.total_audio_energy = 2.0;
2736 expected_audio.total_samples_duration = 3.0;
Taylor Brandstetter64851c02021-06-24 13:32:50 -07002737 expected_audio.echo_return_loss = 42.0;
2738 expected_audio.echo_return_loss_enhancement = 52.0;
Henrik Boström646fda02019-05-22 15:49:42 +02002739
2740 ASSERT_TRUE(report->Get(expected_audio.id()));
2741 EXPECT_EQ(report->Get(expected_audio.id())->cast_to<RTCAudioSourceStats>(),
2742 expected_audio);
2743}
2744
2745TEST_F(RTCStatsCollectorTest, RTCVideoSourceStatsCollectedForSenderWithTrack) {
2746 const uint32_t kSsrc = 4;
2747 const int kAttachmentId = 42;
2748 const int kVideoSourceWidth = 12;
2749 const int kVideoSourceHeight = 34;
2750
2751 cricket::VideoMediaInfo video_media_info;
Henrik Boströma0ff50c2020-05-05 15:54:46 +02002752 video_media_info.aggregated_senders.push_back(cricket::VideoSenderInfo());
Henrik Boström646fda02019-05-22 15:49:42 +02002753 video_media_info.senders.push_back(cricket::VideoSenderInfo());
2754 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
2755 video_media_info.senders[0].local_stats[0].ssrc = kSsrc;
Byoungchan Leeefe46b62021-11-10 11:23:56 +09002756 video_media_info.senders[0].framerate_input = 29.0;
Henrik Boströma0ff50c2020-05-05 15:54:46 +02002757 video_media_info.aggregated_senders[0].local_stats.push_back(
2758 cricket::SsrcSenderInfo());
2759 video_media_info.aggregated_senders[0].local_stats[0].ssrc = kSsrc;
Byoungchan Leeefe46b62021-11-10 11:23:56 +09002760 video_media_info.aggregated_senders[0].framerate_input = 29.0;
Di Wu668dbf62021-02-27 00:29:15 -08002761 video_media_info.aggregated_senders[0].frames = 10001;
Tommi19015512022-02-02 11:49:35 +01002762 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström646fda02019-05-22 15:49:42 +02002763
2764 auto video_source = FakeVideoTrackSourceForStats::Create(kVideoSourceWidth,
2765 kVideoSourceHeight);
2766 auto video_track = FakeVideoTrackForStats::Create(
2767 "LocalVideoTrackID", MediaStreamTrackInterface::kLive, video_source);
2768 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
2769 cricket::MEDIA_TYPE_VIDEO, video_track, kSsrc, kAttachmentId, {});
Tommi6589def2022-02-17 23:36:47 +01002770 EXPECT_CALL(*sender, Stop());
2771 EXPECT_CALL(*sender, SetMediaChannel(_));
Henrik Boström646fda02019-05-22 15:49:42 +02002772 pc_->AddSender(sender);
2773
2774 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
2775
2776 RTCVideoSourceStats expected_video("RTCVideoSource_42",
2777 report->timestamp_us());
2778 expected_video.track_identifier = "LocalVideoTrackID";
2779 expected_video.kind = "video";
2780 expected_video.width = kVideoSourceWidth;
2781 expected_video.height = kVideoSourceHeight;
Byoungchan Leeefe46b62021-11-10 11:23:56 +09002782 expected_video.frames_per_second = 29.0;
Di Wu668dbf62021-02-27 00:29:15 -08002783 expected_video.frames = 10001;
Henrik Boström646fda02019-05-22 15:49:42 +02002784
2785 ASSERT_TRUE(report->Get(expected_video.id()));
2786 EXPECT_EQ(report->Get(expected_video.id())->cast_to<RTCVideoSourceStats>(),
2787 expected_video);
2788}
2789
2790// This test exercises the current behavior and code path, but the correct
2791// behavior is to report frame rate even if we have no SSRC.
2792// TODO(hbos): When we know the frame rate even if we have no SSRC, update the
2793// expectations of this test.
2794TEST_F(RTCStatsCollectorTest,
2795 RTCVideoSourceStatsMissingFrameRateWhenSenderHasNoSsrc) {
2796 // TODO(https://crbug.com/webrtc/8694): When 0 is no longer a magic value for
2797 // "none", update this test.
2798 const uint32_t kNoSsrc = 0;
2799 const int kAttachmentId = 42;
2800 const int kVideoSourceWidth = 12;
2801 const int kVideoSourceHeight = 34;
2802
2803 cricket::VideoMediaInfo video_media_info;
2804 video_media_info.senders.push_back(cricket::VideoSenderInfo());
2805 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
Byoungchan Leeefe46b62021-11-10 11:23:56 +09002806 video_media_info.senders[0].framerate_input = 29.0;
Tommi19015512022-02-02 11:49:35 +01002807 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström646fda02019-05-22 15:49:42 +02002808
2809 auto video_source = FakeVideoTrackSourceForStats::Create(kVideoSourceWidth,
2810 kVideoSourceHeight);
2811 auto video_track = FakeVideoTrackForStats::Create(
2812 "LocalVideoTrackID", MediaStreamTrackInterface::kLive, video_source);
2813 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
2814 cricket::MEDIA_TYPE_VIDEO, video_track, kNoSsrc, kAttachmentId, {});
Tommi6589def2022-02-17 23:36:47 +01002815 EXPECT_CALL(*sender, Stop());
2816 EXPECT_CALL(*sender, SetMediaChannel(_));
Henrik Boström646fda02019-05-22 15:49:42 +02002817 pc_->AddSender(sender);
2818
2819 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
2820 ASSERT_TRUE(report->Get("RTCVideoSource_42"));
2821 auto video_stats =
2822 report->Get("RTCVideoSource_42")->cast_to<RTCVideoSourceStats>();
2823 EXPECT_FALSE(video_stats.frames_per_second.is_defined());
Di Wu668dbf62021-02-27 00:29:15 -08002824 EXPECT_FALSE(video_stats.frames.is_defined());
Henrik Boström646fda02019-05-22 15:49:42 +02002825}
2826
2827// The track not having a source is not expected to be true in practise, but
2828// this is true in some tests relying on fakes. This test covers that code path.
2829TEST_F(RTCStatsCollectorTest,
2830 RTCVideoSourceStatsMissingResolutionWhenTrackHasNoSource) {
2831 const uint32_t kSsrc = 4;
2832 const int kAttachmentId = 42;
2833
2834 cricket::VideoMediaInfo video_media_info;
2835 video_media_info.senders.push_back(cricket::VideoSenderInfo());
2836 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
2837 video_media_info.senders[0].local_stats[0].ssrc = kSsrc;
Byoungchan Leeefe46b62021-11-10 11:23:56 +09002838 video_media_info.senders[0].framerate_input = 29.0;
Tommi19015512022-02-02 11:49:35 +01002839 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström646fda02019-05-22 15:49:42 +02002840
2841 auto video_track = FakeVideoTrackForStats::Create(
2842 "LocalVideoTrackID", MediaStreamTrackInterface::kLive,
2843 /*source=*/nullptr);
2844 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
2845 cricket::MEDIA_TYPE_VIDEO, video_track, kSsrc, kAttachmentId, {});
Tommi6589def2022-02-17 23:36:47 +01002846 EXPECT_CALL(*sender, Stop());
2847 EXPECT_CALL(*sender, SetMediaChannel(_));
Henrik Boström646fda02019-05-22 15:49:42 +02002848 pc_->AddSender(sender);
2849
2850 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
2851 ASSERT_TRUE(report->Get("RTCVideoSource_42"));
2852 auto video_stats =
2853 report->Get("RTCVideoSource_42")->cast_to<RTCVideoSourceStats>();
2854 EXPECT_FALSE(video_stats.width.is_defined());
2855 EXPECT_FALSE(video_stats.height.is_defined());
2856}
2857
2858TEST_F(RTCStatsCollectorTest,
2859 RTCAudioSourceStatsNotCollectedForSenderWithoutTrack) {
2860 const uint32_t kSsrc = 4;
2861 const int kAttachmentId = 42;
2862
2863 cricket::VoiceMediaInfo voice_media_info;
2864 voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
2865 voice_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
2866 voice_media_info.senders[0].local_stats[0].ssrc = kSsrc;
Tommi19015512022-02-02 11:49:35 +01002867 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
Henrik Boström646fda02019-05-22 15:49:42 +02002868 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
2869 cricket::MEDIA_TYPE_AUDIO, /*track=*/nullptr, kSsrc, kAttachmentId, {});
Tommi6589def2022-02-17 23:36:47 +01002870 EXPECT_CALL(*sender, Stop());
2871 EXPECT_CALL(*sender, SetMediaChannel(_));
Henrik Boström646fda02019-05-22 15:49:42 +02002872 pc_->AddSender(sender);
2873
2874 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
2875 EXPECT_FALSE(report->Get("RTCAudioSource_42"));
2876}
2877
Henrik Boström883eefc2019-05-27 13:40:25 +02002878// Parameterized tests on cricket::MediaType (audio or video).
2879class RTCStatsCollectorTestWithParamKind
2880 : public RTCStatsCollectorTest,
2881 public ::testing::WithParamInterface<cricket::MediaType> {
2882 public:
2883 RTCStatsCollectorTestWithParamKind() : media_type_(GetParam()) {
2884 RTC_DCHECK(media_type_ == cricket::MEDIA_TYPE_AUDIO ||
2885 media_type_ == cricket::MEDIA_TYPE_VIDEO);
2886 }
2887
2888 std::string MediaTypeUpperCase() const {
2889 switch (media_type_) {
2890 case cricket::MEDIA_TYPE_AUDIO:
2891 return "Audio";
2892 case cricket::MEDIA_TYPE_VIDEO:
2893 return "Video";
2894 case cricket::MEDIA_TYPE_DATA:
Philipp Hancke4e8c1152020-10-13 12:43:15 +02002895 case cricket::MEDIA_TYPE_UNSUPPORTED:
Artem Titovd3251962021-11-15 16:57:07 +01002896 RTC_DCHECK_NOTREACHED();
Henrik Boström883eefc2019-05-27 13:40:25 +02002897 return "";
2898 }
2899 }
2900
2901 std::string MediaTypeLowerCase() const {
2902 std::string str = MediaTypeUpperCase();
2903 std::transform(str.begin(), str.end(), str.begin(), ::tolower);
2904 return str;
2905 }
2906
2907 // Adds a sender and channel of the appropriate kind, creating a sender info
Artem Titov880fa812021-07-30 22:30:23 +02002908 // with the report block's `source_ssrc` and report block data.
Eldar Relloc07e9042020-07-03 11:08:07 +03002909 void AddSenderInfoAndMediaChannel(
2910 std::string transport_name,
2911 const std::vector<ReportBlockData>& report_block_datas,
2912 absl::optional<RtpCodecParameters> codec) {
Henrik Boström883eefc2019-05-27 13:40:25 +02002913 switch (media_type_) {
2914 case cricket::MEDIA_TYPE_AUDIO: {
2915 cricket::VoiceMediaInfo voice_media_info;
Eldar Relloc07e9042020-07-03 11:08:07 +03002916 for (const auto& report_block_data : report_block_datas) {
2917 cricket::VoiceSenderInfo sender;
2918 sender.local_stats.push_back(cricket::SsrcSenderInfo());
2919 sender.local_stats[0].ssrc =
2920 report_block_data.report_block().source_ssrc;
2921 if (codec.has_value()) {
2922 sender.codec_payload_type = codec->payload_type;
2923 voice_media_info.send_codecs.insert(
2924 std::make_pair(codec->payload_type, *codec));
2925 }
2926 sender.report_block_datas.push_back(report_block_data);
2927 voice_media_info.senders.push_back(sender);
Henrik Boström883eefc2019-05-27 13:40:25 +02002928 }
Tommi19015512022-02-02 11:49:35 +01002929 pc_->AddVoiceChannel("mid", transport_name, voice_media_info);
Henrik Boström883eefc2019-05-27 13:40:25 +02002930 return;
2931 }
2932 case cricket::MEDIA_TYPE_VIDEO: {
2933 cricket::VideoMediaInfo video_media_info;
Eldar Relloc07e9042020-07-03 11:08:07 +03002934 for (const auto& report_block_data : report_block_datas) {
2935 cricket::VideoSenderInfo sender;
2936 sender.local_stats.push_back(cricket::SsrcSenderInfo());
2937 sender.local_stats[0].ssrc =
2938 report_block_data.report_block().source_ssrc;
2939 if (codec.has_value()) {
2940 sender.codec_payload_type = codec->payload_type;
2941 video_media_info.send_codecs.insert(
2942 std::make_pair(codec->payload_type, *codec));
2943 }
2944 sender.report_block_datas.push_back(report_block_data);
2945 video_media_info.aggregated_senders.push_back(sender);
2946 video_media_info.senders.push_back(sender);
Henrik Boström883eefc2019-05-27 13:40:25 +02002947 }
Tommi19015512022-02-02 11:49:35 +01002948 pc_->AddVideoChannel("mid", transport_name, video_media_info);
Henrik Boström883eefc2019-05-27 13:40:25 +02002949 return;
2950 }
2951 case cricket::MEDIA_TYPE_DATA:
Philipp Hancke4e8c1152020-10-13 12:43:15 +02002952 case cricket::MEDIA_TYPE_UNSUPPORTED:
Artem Titovd3251962021-11-15 16:57:07 +01002953 RTC_DCHECK_NOTREACHED();
Henrik Boström883eefc2019-05-27 13:40:25 +02002954 }
2955 }
2956
2957 protected:
2958 cricket::MediaType media_type_;
2959};
2960
2961// Verifies RTCRemoteInboundRtpStreamStats members that don't require
2962// RTCCodecStats (codecId, jitter) and without setting up an RTCP transport.
2963TEST_P(RTCStatsCollectorTestWithParamKind,
2964 RTCRemoteInboundRtpStreamStatsCollectedFromReportBlock) {
2965 const int64_t kReportBlockTimestampUtcUs = 123456789;
Di Wu86f04ad2021-02-28 23:36:03 -08002966 const uint8_t kFractionLost = 12;
Di Wu88a51b22021-03-01 11:22:06 -08002967 const int64_t kRoundTripTimeSample1Ms = 1234;
2968 const double kRoundTripTimeSample1Seconds = 1.234;
2969 const int64_t kRoundTripTimeSample2Ms = 13000;
2970 const double kRoundTripTimeSample2Seconds = 13;
Henrik Boström883eefc2019-05-27 13:40:25 +02002971
2972 // The report block's timestamp cannot be from the future, set the fake clock
2973 // to match.
Danil Chapovalov0c626af2020-02-10 11:16:00 +01002974 fake_clock_.SetTime(Timestamp::Micros(kReportBlockTimestampUtcUs));
Eldar Relloc07e9042020-07-03 11:08:07 +03002975 auto ssrcs = {12, 13};
2976 std::vector<ReportBlockData> report_block_datas;
2977 for (auto ssrc : ssrcs) {
2978 RTCPReportBlock report_block;
2979 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
Artem Titov880fa812021-07-30 22:30:23 +02002980 // `source_ssrc`, "SSRC of the RTP packet sender".
Eldar Relloc07e9042020-07-03 11:08:07 +03002981 report_block.source_ssrc = ssrc;
2982 report_block.packets_lost = 7;
Di Wu86f04ad2021-02-28 23:36:03 -08002983 report_block.fraction_lost = kFractionLost;
Eldar Relloc07e9042020-07-03 11:08:07 +03002984 ReportBlockData report_block_data;
2985 report_block_data.SetReportBlock(report_block, kReportBlockTimestampUtcUs);
Di Wu88a51b22021-03-01 11:22:06 -08002986 report_block_data.AddRoundTripTimeSample(kRoundTripTimeSample1Ms);
Eldar Relloc07e9042020-07-03 11:08:07 +03002987 // Only the last sample should be exposed as the
Artem Titovcfea2182021-08-10 01:22:31 +02002988 // `RTCRemoteInboundRtpStreamStats::round_trip_time`.
Di Wu88a51b22021-03-01 11:22:06 -08002989 report_block_data.AddRoundTripTimeSample(kRoundTripTimeSample2Ms);
Eldar Relloc07e9042020-07-03 11:08:07 +03002990 report_block_datas.push_back(report_block_data);
2991 }
2992 AddSenderInfoAndMediaChannel("TransportName", report_block_datas,
Henrik Boström883eefc2019-05-27 13:40:25 +02002993 absl::nullopt);
2994
2995 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
Eldar Relloc07e9042020-07-03 11:08:07 +03002996 for (auto ssrc : ssrcs) {
2997 std::string stream_id = "Stream_" + std::to_string(ssrc);
2998 RTCRemoteInboundRtpStreamStats expected_remote_inbound_rtp(
2999 "RTCRemoteInboundRtp" + MediaTypeUpperCase() + stream_id,
3000 kReportBlockTimestampUtcUs);
3001 expected_remote_inbound_rtp.ssrc = ssrc;
Di Wu86f04ad2021-02-28 23:36:03 -08003002 expected_remote_inbound_rtp.fraction_lost =
3003 static_cast<double>(kFractionLost) / (1 << 8);
Eldar Relloc07e9042020-07-03 11:08:07 +03003004 expected_remote_inbound_rtp.kind = MediaTypeLowerCase();
3005 expected_remote_inbound_rtp.transport_id =
3006 "RTCTransport_TransportName_1"; // 1 for RTP (we have no RTCP
3007 // transport)
3008 expected_remote_inbound_rtp.packets_lost = 7;
3009 expected_remote_inbound_rtp.local_id =
3010 "RTCOutboundRTP" + MediaTypeUpperCase() + stream_id;
Di Wu88a51b22021-03-01 11:22:06 -08003011 expected_remote_inbound_rtp.round_trip_time = kRoundTripTimeSample2Seconds;
3012 expected_remote_inbound_rtp.total_round_trip_time =
3013 kRoundTripTimeSample1Seconds + kRoundTripTimeSample2Seconds;
3014 expected_remote_inbound_rtp.round_trip_time_measurements = 2;
Artem Titov880fa812021-07-30 22:30:23 +02003015 // This test does not set up RTCCodecStats, so `codec_id` and `jitter` are
Eldar Relloc07e9042020-07-03 11:08:07 +03003016 // expected to be missing. These are tested separately.
Henrik Boström883eefc2019-05-27 13:40:25 +02003017
Eldar Relloc07e9042020-07-03 11:08:07 +03003018 ASSERT_TRUE(report->Get(expected_remote_inbound_rtp.id()));
3019 EXPECT_EQ(report->Get(expected_remote_inbound_rtp.id())
3020 ->cast_to<RTCRemoteInboundRtpStreamStats>(),
3021 expected_remote_inbound_rtp);
3022 EXPECT_TRUE(report->Get(*expected_remote_inbound_rtp.transport_id));
3023 ASSERT_TRUE(report->Get(*expected_remote_inbound_rtp.local_id));
3024 // Lookup works in both directions.
3025 EXPECT_EQ(*report->Get(*expected_remote_inbound_rtp.local_id)
3026 ->cast_to<RTCOutboundRTPStreamStats>()
3027 .remote_id,
3028 expected_remote_inbound_rtp.id());
3029 }
Henrik Boström883eefc2019-05-27 13:40:25 +02003030}
3031
3032TEST_P(RTCStatsCollectorTestWithParamKind,
3033 RTCRemoteInboundRtpStreamStatsWithTimestampFromReportBlock) {
3034 const int64_t kReportBlockTimestampUtcUs = 123456789;
Danil Chapovalov0c626af2020-02-10 11:16:00 +01003035 fake_clock_.SetTime(Timestamp::Micros(kReportBlockTimestampUtcUs));
Henrik Boström883eefc2019-05-27 13:40:25 +02003036
3037 RTCPReportBlock report_block;
Henrik Boström8605fbf2019-06-24 16:44:51 +02003038 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
Artem Titov880fa812021-07-30 22:30:23 +02003039 // `source_ssrc`, "SSRC of the RTP packet sender".
Henrik Boström883eefc2019-05-27 13:40:25 +02003040 report_block.source_ssrc = 12;
3041 ReportBlockData report_block_data;
3042 report_block_data.SetReportBlock(report_block, kReportBlockTimestampUtcUs);
3043
Eldar Relloc07e9042020-07-03 11:08:07 +03003044 AddSenderInfoAndMediaChannel("TransportName", {report_block_data},
Henrik Boström883eefc2019-05-27 13:40:25 +02003045 absl::nullopt);
3046
3047 // Advance time, it should be OK to have fresher reports than report blocks.
Danil Chapovalov0c626af2020-02-10 11:16:00 +01003048 fake_clock_.AdvanceTime(TimeDelta::Micros(1234));
Henrik Boström883eefc2019-05-27 13:40:25 +02003049
3050 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3051
3052 std::string remote_inbound_rtp_id =
Henrik Boström8605fbf2019-06-24 16:44:51 +02003053 "RTCRemoteInboundRtp" + MediaTypeUpperCase() + "Stream_12";
Henrik Boström883eefc2019-05-27 13:40:25 +02003054 ASSERT_TRUE(report->Get(remote_inbound_rtp_id));
3055 auto& remote_inbound_rtp = report->Get(remote_inbound_rtp_id)
3056 ->cast_to<RTCRemoteInboundRtpStreamStats>();
3057
3058 // Even though the report time is different, the remote-inbound-rtp timestamp
3059 // is of the time that the report block was received.
3060 EXPECT_EQ(kReportBlockTimestampUtcUs + 1234, report->timestamp_us());
3061 EXPECT_EQ(kReportBlockTimestampUtcUs, remote_inbound_rtp.timestamp_us());
3062}
3063
3064TEST_P(RTCStatsCollectorTestWithParamKind,
3065 RTCRemoteInboundRtpStreamStatsWithCodecBasedMembers) {
3066 const int64_t kReportBlockTimestampUtcUs = 123456789;
Danil Chapovalov0c626af2020-02-10 11:16:00 +01003067 fake_clock_.SetTime(Timestamp::Micros(kReportBlockTimestampUtcUs));
Henrik Boström883eefc2019-05-27 13:40:25 +02003068
3069 RTCPReportBlock report_block;
Henrik Boström8605fbf2019-06-24 16:44:51 +02003070 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
Artem Titov880fa812021-07-30 22:30:23 +02003071 // `source_ssrc`, "SSRC of the RTP packet sender".
Henrik Boström883eefc2019-05-27 13:40:25 +02003072 report_block.source_ssrc = 12;
3073 report_block.jitter = 5000;
3074 ReportBlockData report_block_data;
3075 report_block_data.SetReportBlock(report_block, kReportBlockTimestampUtcUs);
3076
3077 RtpCodecParameters codec;
3078 codec.payload_type = 3;
3079 codec.kind = media_type_;
3080 codec.clock_rate = 1000;
3081
Eldar Relloc07e9042020-07-03 11:08:07 +03003082 AddSenderInfoAndMediaChannel("TransportName", {report_block_data}, codec);
Henrik Boström883eefc2019-05-27 13:40:25 +02003083
3084 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3085
3086 std::string remote_inbound_rtp_id =
Henrik Boström8605fbf2019-06-24 16:44:51 +02003087 "RTCRemoteInboundRtp" + MediaTypeUpperCase() + "Stream_12";
Henrik Boström883eefc2019-05-27 13:40:25 +02003088 ASSERT_TRUE(report->Get(remote_inbound_rtp_id));
3089 auto& remote_inbound_rtp = report->Get(remote_inbound_rtp_id)
3090 ->cast_to<RTCRemoteInboundRtpStreamStats>();
3091
3092 EXPECT_TRUE(remote_inbound_rtp.codec_id.is_defined());
3093 EXPECT_TRUE(report->Get(*remote_inbound_rtp.codec_id));
3094
3095 EXPECT_TRUE(remote_inbound_rtp.jitter.is_defined());
3096 // The jitter (in seconds) is the report block's jitter divided by the codec's
3097 // clock rate.
3098 EXPECT_EQ(5.0, *remote_inbound_rtp.jitter);
3099}
3100
3101TEST_P(RTCStatsCollectorTestWithParamKind,
3102 RTCRemoteInboundRtpStreamStatsWithRtcpTransport) {
3103 const int64_t kReportBlockTimestampUtcUs = 123456789;
Danil Chapovalov0c626af2020-02-10 11:16:00 +01003104 fake_clock_.SetTime(Timestamp::Micros(kReportBlockTimestampUtcUs));
Henrik Boström883eefc2019-05-27 13:40:25 +02003105
3106 RTCPReportBlock report_block;
Henrik Boström8605fbf2019-06-24 16:44:51 +02003107 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
Artem Titov880fa812021-07-30 22:30:23 +02003108 // `source_ssrc`, "SSRC of the RTP packet sender".
Henrik Boström883eefc2019-05-27 13:40:25 +02003109 report_block.source_ssrc = 12;
3110 ReportBlockData report_block_data;
3111 report_block_data.SetReportBlock(report_block, kReportBlockTimestampUtcUs);
3112
3113 cricket::TransportChannelStats rtp_transport_channel_stats;
3114 rtp_transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
Mirko Bonadei9f6808b2021-05-21 20:46:09 +02003115 rtp_transport_channel_stats.dtls_state = DtlsTransportState::kNew;
Henrik Boström883eefc2019-05-27 13:40:25 +02003116 cricket::TransportChannelStats rtcp_transport_channel_stats;
3117 rtcp_transport_channel_stats.component =
3118 cricket::ICE_CANDIDATE_COMPONENT_RTCP;
Mirko Bonadei9f6808b2021-05-21 20:46:09 +02003119 rtcp_transport_channel_stats.dtls_state = DtlsTransportState::kNew;
Henrik Boström883eefc2019-05-27 13:40:25 +02003120 pc_->SetTransportStats("TransportName", {rtp_transport_channel_stats,
3121 rtcp_transport_channel_stats});
Eldar Relloc07e9042020-07-03 11:08:07 +03003122 AddSenderInfoAndMediaChannel("TransportName", {report_block_data},
Henrik Boström883eefc2019-05-27 13:40:25 +02003123 absl::nullopt);
3124
3125 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3126
3127 std::string remote_inbound_rtp_id =
Henrik Boström8605fbf2019-06-24 16:44:51 +02003128 "RTCRemoteInboundRtp" + MediaTypeUpperCase() + "Stream_12";
Henrik Boström883eefc2019-05-27 13:40:25 +02003129 ASSERT_TRUE(report->Get(remote_inbound_rtp_id));
3130 auto& remote_inbound_rtp = report->Get(remote_inbound_rtp_id)
3131 ->cast_to<RTCRemoteInboundRtpStreamStats>();
3132
3133 EXPECT_TRUE(remote_inbound_rtp.transport_id.is_defined());
3134 EXPECT_EQ("RTCTransport_TransportName_2", // 2 for RTCP
3135 *remote_inbound_rtp.transport_id);
3136 EXPECT_TRUE(report->Get(*remote_inbound_rtp.transport_id));
3137}
3138
Mirko Bonadei1b575412019-09-23 08:34:50 +02003139INSTANTIATE_TEST_SUITE_P(All,
Henrik Boström883eefc2019-05-27 13:40:25 +02003140 RTCStatsCollectorTestWithParamKind,
3141 ::testing::Values(cricket::MEDIA_TYPE_AUDIO, // "/0"
3142 cricket::MEDIA_TYPE_VIDEO)); // "/1"
3143
Alessio Bazzicaf7b1b952021-03-23 17:23:04 +01003144// Checks that no remote outbound stats are collected if not available in
3145// `VoiceMediaInfo`.
3146TEST_F(RTCStatsCollectorTest,
3147 RTCRemoteOutboundRtpAudioStreamStatsNotCollected) {
3148 ExampleStatsGraph graph =
3149 SetupExampleStatsVoiceGraph(/*add_remote_outbound_stats=*/false);
3150 EXPECT_FALSE(graph.full_report->Get(graph.remote_outbound_rtp_id));
3151 // Also check that no other remote outbound report is created (in case the
3152 // expected ID is incorrect).
3153 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3154 ASSERT_NE(report->begin(), report->end())
3155 << "No reports have been generated.";
3156 for (const auto& stats : *report) {
3157 SCOPED_TRACE(stats.id());
3158 EXPECT_NE(stats.type(), RTCRemoteOutboundRtpStreamStats::kType);
3159 }
3160}
3161
3162// Checks that the remote outbound stats are collected when available in
3163// `VoiceMediaInfo`.
3164TEST_F(RTCStatsCollectorTest, RTCRemoteOutboundRtpAudioStreamStatsCollected) {
3165 ExampleStatsGraph graph =
3166 SetupExampleStatsVoiceGraph(/*add_remote_outbound_stats=*/true);
3167 ASSERT_TRUE(graph.full_report->Get(graph.remote_outbound_rtp_id));
3168 const auto& remote_outbound_rtp =
3169 graph.full_report->Get(graph.remote_outbound_rtp_id)
3170 ->cast_to<RTCRemoteOutboundRtpStreamStats>();
3171 EXPECT_EQ(remote_outbound_rtp.timestamp_us(),
3172 kRemoteOutboundStatsTimestampMs * rtc::kNumMicrosecsPerMillisec);
3173 EXPECT_FLOAT_EQ(*remote_outbound_rtp.remote_timestamp,
3174 static_cast<double>(kRemoteOutboundStatsRemoteTimestampMs));
3175 EXPECT_EQ(*remote_outbound_rtp.packets_sent, kRemoteOutboundStatsPacketsSent);
3176 EXPECT_EQ(*remote_outbound_rtp.bytes_sent, kRemoteOutboundStatsBytesSent);
3177 EXPECT_EQ(*remote_outbound_rtp.reports_sent,
3178 kRemoteOutboundStatsReportsCount);
3179}
3180
Henrik Boström646fda02019-05-22 15:49:42 +02003181TEST_F(RTCStatsCollectorTest,
3182 RTCVideoSourceStatsNotCollectedForSenderWithoutTrack) {
3183 const uint32_t kSsrc = 4;
3184 const int kAttachmentId = 42;
3185
3186 cricket::VideoMediaInfo video_media_info;
3187 video_media_info.senders.push_back(cricket::VideoSenderInfo());
3188 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3189 video_media_info.senders[0].local_stats[0].ssrc = kSsrc;
Byoungchan Leeefe46b62021-11-10 11:23:56 +09003190 video_media_info.senders[0].framerate_input = 29.0;
Tommi19015512022-02-02 11:49:35 +01003191 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
Henrik Boström646fda02019-05-22 15:49:42 +02003192
3193 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
3194 cricket::MEDIA_TYPE_VIDEO, /*track=*/nullptr, kSsrc, kAttachmentId, {});
Tommi6589def2022-02-17 23:36:47 +01003195 EXPECT_CALL(*sender, Stop());
3196 EXPECT_CALL(*sender, SetMediaChannel(_));
Henrik Boström646fda02019-05-22 15:49:42 +02003197 pc_->AddSender(sender);
3198
3199 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3200 EXPECT_FALSE(report->Get("RTCVideoSource_42"));
3201}
3202
Taylor Brandstetter64851c02021-06-24 13:32:50 -07003203// Test collecting echo return loss stats from the audio processor attached to
3204// the track, rather than the voice sender info.
3205TEST_F(RTCStatsCollectorTest, CollectEchoReturnLossFromTrackAudioProcessor) {
3206 rtc::scoped_refptr<MediaStream> local_stream =
3207 MediaStream::Create("LocalStreamId");
3208 pc_->mutable_local_streams()->AddStream(local_stream);
3209
3210 // Local audio track
3211 rtc::scoped_refptr<MediaStreamTrackInterface> local_audio_track =
3212 CreateFakeTrack(cricket::MEDIA_TYPE_AUDIO, "LocalAudioTrackID",
3213 MediaStreamTrackInterface::kEnded,
3214 /*create_fake_audio_processor=*/true);
Harald Alvestrand2f7ad282022-04-21 11:35:43 +00003215 local_stream->AddTrack(rtc::scoped_refptr<AudioTrackInterface>(
3216 static_cast<AudioTrackInterface*>(local_audio_track.get())));
Taylor Brandstetter64851c02021-06-24 13:32:50 -07003217
3218 cricket::VoiceSenderInfo voice_sender_info_ssrc1;
3219 voice_sender_info_ssrc1.local_stats.push_back(cricket::SsrcSenderInfo());
3220 voice_sender_info_ssrc1.local_stats[0].ssrc = 1;
3221
3222 stats_->CreateMockRtpSendersReceiversAndChannels(
3223 {std::make_pair(local_audio_track.get(), voice_sender_info_ssrc1)}, {},
3224 {}, {}, {local_stream->id()}, {});
3225
3226 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3227
3228 RTCMediaStreamTrackStats expected_local_audio_track_ssrc1(
Niels Möllerafb246b2022-04-20 14:26:50 +02003229 IdForType<RTCMediaStreamTrackStats>(report.get()), report->timestamp_us(),
Taylor Brandstetter64851c02021-06-24 13:32:50 -07003230 RTCMediaStreamTrackKind::kAudio);
3231 expected_local_audio_track_ssrc1.track_identifier = local_audio_track->id();
3232 expected_local_audio_track_ssrc1.media_source_id =
3233 "RTCAudioSource_11"; // Attachment ID = SSRC + 10
3234 expected_local_audio_track_ssrc1.remote_source = false;
3235 expected_local_audio_track_ssrc1.ended = true;
3236 expected_local_audio_track_ssrc1.detached = false;
3237 expected_local_audio_track_ssrc1.echo_return_loss = 2.0;
3238 expected_local_audio_track_ssrc1.echo_return_loss_enhancement = 3.0;
3239 ASSERT_TRUE(report->Get(expected_local_audio_track_ssrc1.id()))
3240 << "Did not find " << expected_local_audio_track_ssrc1.id() << " in "
3241 << report->ToJson();
3242 EXPECT_EQ(expected_local_audio_track_ssrc1,
3243 report->Get(expected_local_audio_track_ssrc1.id())
3244 ->cast_to<RTCMediaStreamTrackStats>());
3245
3246 RTCAudioSourceStats expected_audio("RTCAudioSource_11",
3247 report->timestamp_us());
3248 expected_audio.track_identifier = "LocalAudioTrackID";
3249 expected_audio.kind = "audio";
3250 expected_audio.audio_level = 0;
3251 expected_audio.total_audio_energy = 0;
3252 expected_audio.total_samples_duration = 0;
3253 expected_audio.echo_return_loss = 2.0;
3254 expected_audio.echo_return_loss_enhancement = 3.0;
3255
3256 ASSERT_TRUE(report->Get(expected_audio.id()));
3257 EXPECT_EQ(report->Get(expected_audio.id())->cast_to<RTCAudioSourceStats>(),
3258 expected_audio);
3259}
3260
Henrik Boström5b3541f2018-03-19 13:52:56 +01003261TEST_F(RTCStatsCollectorTest, GetStatsWithSenderSelector) {
3262 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
3263 // Expected stats graph when filtered by sender:
3264 //
Henrik Boström646fda02019-05-22 15:49:42 +02003265 // +--- track (sender)
3266 // | ^
3267 // | |
3268 // | +--------- outbound-rtp
3269 // | | | |
3270 // | | v v
3271 // | | codec (send) transport
3272 // v v
3273 // media-source
Henrik Boström5b3541f2018-03-19 13:52:56 +01003274 rtc::scoped_refptr<const RTCStatsReport> sender_report =
3275 stats_->GetStatsReportWithSenderSelector(graph.sender);
3276 EXPECT_TRUE(sender_report);
3277 EXPECT_EQ(sender_report->timestamp_us(), graph.full_report->timestamp_us());
Henrik Boström646fda02019-05-22 15:49:42 +02003278 EXPECT_EQ(sender_report->size(), 5u);
Henrik Boström5b3541f2018-03-19 13:52:56 +01003279 EXPECT_TRUE(sender_report->Get(graph.send_codec_id));
3280 EXPECT_FALSE(sender_report->Get(graph.recv_codec_id));
3281 EXPECT_TRUE(sender_report->Get(graph.outbound_rtp_id));
3282 EXPECT_FALSE(sender_report->Get(graph.inbound_rtp_id));
3283 EXPECT_TRUE(sender_report->Get(graph.transport_id));
3284 EXPECT_TRUE(sender_report->Get(graph.sender_track_id));
3285 EXPECT_FALSE(sender_report->Get(graph.receiver_track_id));
3286 EXPECT_FALSE(sender_report->Get(graph.remote_stream_id));
3287 EXPECT_FALSE(sender_report->Get(graph.peer_connection_id));
Henrik Boström646fda02019-05-22 15:49:42 +02003288 EXPECT_TRUE(sender_report->Get(graph.media_source_id));
Henrik Boström5b3541f2018-03-19 13:52:56 +01003289}
3290
3291TEST_F(RTCStatsCollectorTest, GetStatsWithReceiverSelector) {
3292 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
3293 // Expected stats graph when filtered by receiver:
3294 //
Henrik Boström646fda02019-05-22 15:49:42 +02003295 // track (receiver)
3296 // ^
3297 // |
3298 // inbound-rtp ---------------+
3299 // | |
3300 // v v
3301 // transport codec (recv)
Henrik Boström5b3541f2018-03-19 13:52:56 +01003302 rtc::scoped_refptr<const RTCStatsReport> receiver_report =
3303 stats_->GetStatsReportWithReceiverSelector(graph.receiver);
3304 EXPECT_TRUE(receiver_report);
3305 EXPECT_EQ(receiver_report->size(), 4u);
3306 EXPECT_EQ(receiver_report->timestamp_us(), graph.full_report->timestamp_us());
3307 EXPECT_FALSE(receiver_report->Get(graph.send_codec_id));
3308 EXPECT_TRUE(receiver_report->Get(graph.recv_codec_id));
3309 EXPECT_FALSE(receiver_report->Get(graph.outbound_rtp_id));
3310 EXPECT_TRUE(receiver_report->Get(graph.inbound_rtp_id));
3311 EXPECT_TRUE(receiver_report->Get(graph.transport_id));
3312 EXPECT_FALSE(receiver_report->Get(graph.sender_track_id));
3313 EXPECT_TRUE(receiver_report->Get(graph.receiver_track_id));
3314 EXPECT_FALSE(receiver_report->Get(graph.remote_stream_id));
3315 EXPECT_FALSE(receiver_report->Get(graph.peer_connection_id));
Henrik Boström646fda02019-05-22 15:49:42 +02003316 EXPECT_FALSE(receiver_report->Get(graph.media_source_id));
Henrik Boström5b3541f2018-03-19 13:52:56 +01003317}
3318
3319TEST_F(RTCStatsCollectorTest, GetStatsWithNullSenderSelector) {
3320 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
3321 rtc::scoped_refptr<const RTCStatsReport> empty_report =
3322 stats_->GetStatsReportWithSenderSelector(nullptr);
3323 EXPECT_TRUE(empty_report);
3324 EXPECT_EQ(empty_report->timestamp_us(), graph.full_report->timestamp_us());
3325 EXPECT_EQ(empty_report->size(), 0u);
3326}
3327
3328TEST_F(RTCStatsCollectorTest, GetStatsWithNullReceiverSelector) {
3329 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
3330 rtc::scoped_refptr<const RTCStatsReport> empty_report =
3331 stats_->GetStatsReportWithReceiverSelector(nullptr);
3332 EXPECT_TRUE(empty_report);
3333 EXPECT_EQ(empty_report->timestamp_us(), graph.full_report->timestamp_us());
3334 EXPECT_EQ(empty_report->size(), 0u);
3335}
3336
Harald Alvestrand89061872018-01-02 14:08:34 +01003337// When the PC has not had SetLocalDescription done, tracks all have
3338// SSRC 0, meaning "unconnected".
Harald Alvestrandb8e12012018-01-23 15:28:16 +01003339// In this state, we report on track stats, but not RTP stats.
3340TEST_F(RTCStatsCollectorTest, StatsReportedOnZeroSsrc) {
Harald Alvestrand89061872018-01-02 14:08:34 +01003341 rtc::scoped_refptr<MediaStreamTrackInterface> track =
3342 CreateFakeTrack(cricket::MEDIA_TYPE_AUDIO, "audioTrack",
3343 MediaStreamTrackInterface::kLive);
Steve Anton57858b32018-02-15 15:19:50 -08003344 rtc::scoped_refptr<MockRtpSenderInternal> sender =
Henrik Boström646fda02019-05-22 15:49:42 +02003345 CreateMockSender(cricket::MEDIA_TYPE_AUDIO, track, 0, 49, {});
Tommi6589def2022-02-17 23:36:47 +01003346 EXPECT_CALL(*sender, Stop());
Steve Anton5b387312018-02-02 16:00:20 -08003347 pc_->AddSender(sender);
3348
3349 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3350
Harald Alvestrand89061872018-01-02 14:08:34 +01003351 std::vector<const RTCMediaStreamTrackStats*> track_stats =
3352 report->GetStatsOfType<RTCMediaStreamTrackStats>();
Mirko Bonadeie12c1fe2018-07-03 12:53:23 +02003353 EXPECT_EQ(1U, track_stats.size());
Steve Anton5b387312018-02-02 16:00:20 -08003354
Harald Alvestrandb8e12012018-01-23 15:28:16 +01003355 std::vector<const RTCRTPStreamStats*> rtp_stream_stats =
3356 report->GetStatsOfType<RTCRTPStreamStats>();
Mirko Bonadeie12c1fe2018-07-03 12:53:23 +02003357 EXPECT_EQ(0U, rtp_stream_stats.size());
Harald Alvestrand89061872018-01-02 14:08:34 +01003358}
3359
Harald Alvestrand76d29522018-01-30 14:43:29 +01003360TEST_F(RTCStatsCollectorTest, DoNotCrashOnSsrcChange) {
3361 rtc::scoped_refptr<MediaStreamTrackInterface> track =
3362 CreateFakeTrack(cricket::MEDIA_TYPE_AUDIO, "audioTrack",
3363 MediaStreamTrackInterface::kLive);
Steve Anton57858b32018-02-15 15:19:50 -08003364 rtc::scoped_refptr<MockRtpSenderInternal> sender =
Henrik Boström646fda02019-05-22 15:49:42 +02003365 CreateMockSender(cricket::MEDIA_TYPE_AUDIO, track, 4711, 49, {});
Tommi6589def2022-02-17 23:36:47 +01003366 EXPECT_CALL(*sender, Stop());
Steve Anton5b387312018-02-02 16:00:20 -08003367 pc_->AddSender(sender);
3368
Harald Alvestrand76d29522018-01-30 14:43:29 +01003369 // We do not generate any matching voice_sender_info stats.
Steve Anton5b387312018-02-02 16:00:20 -08003370 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3371
Harald Alvestrand76d29522018-01-30 14:43:29 +01003372 std::vector<const RTCMediaStreamTrackStats*> track_stats =
3373 report->GetStatsOfType<RTCMediaStreamTrackStats>();
Mirko Bonadeie12c1fe2018-07-03 12:53:23 +02003374 EXPECT_EQ(1U, track_stats.size());
Harald Alvestrand76d29522018-01-30 14:43:29 +01003375}
3376
Taylor Brandstetter87d5a742018-03-06 09:42:25 -08003377// Used for test below, to test calling GetStatsReport during a callback.
Taylor Brandstetter25e022f2018-03-08 09:53:47 -08003378class RecursiveCallback : public RTCStatsCollectorCallback {
Taylor Brandstetter87d5a742018-03-06 09:42:25 -08003379 public:
Taylor Brandstetter25e022f2018-03-08 09:53:47 -08003380 explicit RecursiveCallback(RTCStatsCollectorWrapper* stats) : stats_(stats) {}
Taylor Brandstetter87d5a742018-03-06 09:42:25 -08003381
3382 void OnStatsDelivered(
3383 const rtc::scoped_refptr<const RTCStatsReport>& report) override {
3384 stats_->GetStatsReport();
3385 called_ = true;
3386 }
3387
3388 bool called() const { return called_; }
3389
3390 private:
3391 RTCStatsCollectorWrapper* stats_;
3392 bool called_ = false;
3393};
3394
3395// Test that nothing bad happens if a callback causes GetStatsReport to be
3396// called again recursively. Regression test for crbug.com/webrtc/8973.
Taylor Brandstetter25e022f2018-03-08 09:53:47 -08003397TEST_F(RTCStatsCollectorTest, DoNotCrashWhenGetStatsCalledDuringCallback) {
Niels Möller027c7932022-01-25 13:56:07 +01003398 auto callback1 = rtc::make_ref_counted<RecursiveCallback>(stats_.get());
3399 auto callback2 = rtc::make_ref_counted<RecursiveCallback>(stats_.get());
Taylor Brandstetter87d5a742018-03-06 09:42:25 -08003400 stats_->stats_collector()->GetStatsReport(callback1);
3401 stats_->stats_collector()->GetStatsReport(callback2);
3402 EXPECT_TRUE_WAIT(callback1->called(), kGetStatsReportTimeoutMs);
3403 EXPECT_TRUE_WAIT(callback2->called(), kGetStatsReportTimeoutMs);
3404}
3405
Steve Anton5b387312018-02-02 16:00:20 -08003406class RTCTestStats : public RTCStats {
hbosc82f2e12016-09-05 01:36:50 -07003407 public:
Steve Anton5b387312018-02-02 16:00:20 -08003408 WEBRTC_RTCSTATS_DECL();
3409
3410 RTCTestStats(const std::string& id, int64_t timestamp_us)
3411 : RTCStats(id, timestamp_us), dummy_stat("dummyStat") {}
3412
3413 RTCStatsMember<int32_t> dummy_stat;
3414};
3415
Mirko Bonadeic4dd7302019-02-25 09:12:02 +01003416WEBRTC_RTCSTATS_IMPL(RTCTestStats, RTCStats, "test-stats", &dummy_stat)
Steve Anton5b387312018-02-02 16:00:20 -08003417
3418// Overrides the stats collection to verify thread usage and that the resulting
3419// partial reports are merged.
3420class FakeRTCStatsCollector : public RTCStatsCollector,
3421 public RTCStatsCollectorCallback {
3422 public:
3423 static rtc::scoped_refptr<FakeRTCStatsCollector> Create(
3424 PeerConnectionInternal* pc,
3425 int64_t cache_lifetime_us) {
Niels Möllere7cc8832022-01-04 15:20:03 +01003426 return rtc::scoped_refptr<FakeRTCStatsCollector>(
3427 new rtc::RefCountedObject<FakeRTCStatsCollector>(pc,
3428 cache_lifetime_us));
Steve Anton5b387312018-02-02 16:00:20 -08003429 }
3430
Tomas Gunnarssone6de5ae2021-04-22 18:16:35 +02003431 // Since FakeRTCStatsCollector inherits twice from RefCountInterface, once via
3432 // RTCStatsCollector and once via RTCStatsCollectorCallback, scoped_refptr
3433 // will get confused about which AddRef()/Release() methods to call.
3434 // So to remove all doubt, we declare them here again in the class that we
3435 // give to scoped_refptr.
3436 // Satisfying the implementation of these methods and associating them with a
3437 // reference counter, will be done by RefCountedObject.
3438 virtual void AddRef() const = 0;
3439 virtual rtc::RefCountReleaseStatus Release() const = 0;
3440
Steve Anton5b387312018-02-02 16:00:20 -08003441 // RTCStatsCollectorCallback implementation.
3442 void OnStatsDelivered(
3443 const rtc::scoped_refptr<const RTCStatsReport>& report) override {
3444 EXPECT_TRUE(signaling_thread_->IsCurrent());
Markus Handell6fcd0f82020-07-07 19:08:53 +02003445 MutexLock lock(&lock_);
Steve Anton5b387312018-02-02 16:00:20 -08003446 delivered_report_ = report;
3447 }
3448
3449 void VerifyThreadUsageAndResultsMerging() {
3450 GetStatsReport(rtc::scoped_refptr<RTCStatsCollectorCallback>(this));
3451 EXPECT_TRUE_WAIT(HasVerifiedResults(), kGetStatsReportTimeoutMs);
3452 }
3453
3454 bool HasVerifiedResults() {
3455 EXPECT_TRUE(signaling_thread_->IsCurrent());
Markus Handell6fcd0f82020-07-07 19:08:53 +02003456 MutexLock lock(&lock_);
Steve Anton5b387312018-02-02 16:00:20 -08003457 if (!delivered_report_)
3458 return false;
3459 EXPECT_EQ(produced_on_signaling_thread_, 1);
3460 EXPECT_EQ(produced_on_network_thread_, 1);
3461
3462 EXPECT_TRUE(delivered_report_->Get("SignalingThreadStats"));
3463 EXPECT_TRUE(delivered_report_->Get("NetworkThreadStats"));
3464
3465 produced_on_signaling_thread_ = 0;
3466 produced_on_network_thread_ = 0;
3467 delivered_report_ = nullptr;
3468 return true;
hbosc82f2e12016-09-05 01:36:50 -07003469 }
3470
3471 protected:
Steve Anton5b387312018-02-02 16:00:20 -08003472 FakeRTCStatsCollector(PeerConnectionInternal* pc, int64_t cache_lifetime)
3473 : RTCStatsCollector(pc, cache_lifetime),
3474 signaling_thread_(pc->signaling_thread()),
3475 worker_thread_(pc->worker_thread()),
3476 network_thread_(pc->network_thread()) {}
3477
Henrik Boström40b030e2019-02-28 09:49:31 +01003478 void ProducePartialResultsOnSignalingThreadImpl(
3479 int64_t timestamp_us,
3480 RTCStatsReport* partial_report) override {
Steve Anton5b387312018-02-02 16:00:20 -08003481 EXPECT_TRUE(signaling_thread_->IsCurrent());
3482 {
Markus Handell6fcd0f82020-07-07 19:08:53 +02003483 MutexLock lock(&lock_);
Steve Anton5b387312018-02-02 16:00:20 -08003484 EXPECT_FALSE(delivered_report_);
3485 ++produced_on_signaling_thread_;
3486 }
3487
Henrik Boström40b030e2019-02-28 09:49:31 +01003488 partial_report->AddStats(std::unique_ptr<const RTCStats>(
Steve Anton5b387312018-02-02 16:00:20 -08003489 new RTCTestStats("SignalingThreadStats", timestamp_us)));
Steve Anton5b387312018-02-02 16:00:20 -08003490 }
Henrik Boström40b030e2019-02-28 09:49:31 +01003491 void ProducePartialResultsOnNetworkThreadImpl(
3492 int64_t timestamp_us,
3493 const std::map<std::string, cricket::TransportStats>&
3494 transport_stats_by_name,
3495 const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
3496 RTCStatsReport* partial_report) override {
Steve Anton5b387312018-02-02 16:00:20 -08003497 EXPECT_TRUE(network_thread_->IsCurrent());
3498 {
Markus Handell6fcd0f82020-07-07 19:08:53 +02003499 MutexLock lock(&lock_);
Steve Anton5b387312018-02-02 16:00:20 -08003500 EXPECT_FALSE(delivered_report_);
3501 ++produced_on_network_thread_;
3502 }
3503
Henrik Boström40b030e2019-02-28 09:49:31 +01003504 partial_report->AddStats(std::unique_ptr<const RTCStats>(
Steve Anton5b387312018-02-02 16:00:20 -08003505 new RTCTestStats("NetworkThreadStats", timestamp_us)));
Steve Anton5b387312018-02-02 16:00:20 -08003506 }
3507
3508 private:
3509 rtc::Thread* const signaling_thread_;
3510 rtc::Thread* const worker_thread_;
3511 rtc::Thread* const network_thread_;
3512
Markus Handell6fcd0f82020-07-07 19:08:53 +02003513 Mutex lock_;
Steve Anton5b387312018-02-02 16:00:20 -08003514 rtc::scoped_refptr<const RTCStatsReport> delivered_report_;
3515 int produced_on_signaling_thread_ = 0;
3516 int produced_on_network_thread_ = 0;
hbosc82f2e12016-09-05 01:36:50 -07003517};
3518
Steve Anton5b387312018-02-02 16:00:20 -08003519TEST(RTCStatsCollectorTestWithFakeCollector, ThreadUsageAndResultsMerging) {
Niels Möller027c7932022-01-25 13:56:07 +01003520 auto pc = rtc::make_ref_counted<FakePeerConnectionForStats>();
Steve Anton5b387312018-02-02 16:00:20 -08003521 rtc::scoped_refptr<FakeRTCStatsCollector> stats_collector(
Niels Möllerafb246b2022-04-20 14:26:50 +02003522 FakeRTCStatsCollector::Create(pc.get(),
3523 50 * rtc::kNumMicrosecsPerMillisec));
Steve Anton5b387312018-02-02 16:00:20 -08003524 stats_collector->VerifyThreadUsageAndResultsMerging();
hbosc82f2e12016-09-05 01:36:50 -07003525}
3526
3527} // namespace
3528
hbosd565b732016-08-30 14:04:35 -07003529} // namespace webrtc