1 /*
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
11 #include "pc/rtc_stats_collector.h"
12
13 #include <stddef.h>
14 #include <stdint.h>
15
16 #include <algorithm>
17 #include <initializer_list>
18 #include <memory>
19 #include <ostream>
20 #include <string>
21 #include <type_traits>
22 #include <utility>
23 #include <vector>
24
25 #include "absl/strings/str_replace.h"
26 #include "api/candidate.h"
27 #include "api/dtls_transport_interface.h"
28 #include "api/media_stream_interface.h"
29 #include "api/media_stream_track.h"
30 #include "api/rtp_parameters.h"
31 #include "api/stats/rtc_stats.h"
32 #include "api/stats/rtc_stats_report.h"
33 #include "api/stats/rtcstats_objects.h"
34 #include "api/units/time_delta.h"
35 #include "api/units/timestamp.h"
36 #include "api/video/recordable_encoded_frame.h"
37 #include "api/video/video_content_type.h"
38 #include "api/video/video_frame.h"
39 #include "api/video/video_sink_interface.h"
40 #include "api/video/video_source_interface.h"
41 #include "api/video/video_timing.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"
45 #include "modules/rtp_rtcp/include/report_block_data.h"
46 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
47 #include "p2p/base/connection_info.h"
48 #include "p2p/base/ice_transport_internal.h"
49 #include "p2p/base/p2p_constants.h"
50 #include "p2p/base/port.h"
51 #include "pc/media_stream.h"
52 #include "pc/stream_collection.h"
53 #include "pc/test/fake_data_channel_controller.h"
54 #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"
59 #include "rtc_base/checks.h"
60 #include "rtc_base/fake_clock.h"
61 #include "rtc_base/fake_ssl_identity.h"
62 #include "rtc_base/gunit.h"
63 #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"
71 #include "rtc_base/strings/json.h"
72 #include "rtc_base/synchronization/mutex.h"
73 #include "rtc_base/time_utils.h"
74 #include "test/gmock.h"
75 #include "test/gtest.h"
76
77 using ::testing::_;
78 using ::testing::AtLeast;
79 using ::testing::Invoke;
80 using ::testing::Return;
81
82 namespace webrtc {
83
84 // These are used by gtest code, such as if `EXPECT_EQ` fails.
PrintTo(const RTCCertificateStats & stats,::std::ostream * os)85 void PrintTo(const RTCCertificateStats& stats, ::std::ostream* os) {
86 *os << stats.ToJson();
87 }
88
PrintTo(const RTCCodecStats & stats,::std::ostream * os)89 void PrintTo(const RTCCodecStats& stats, ::std::ostream* os) {
90 *os << stats.ToJson();
91 }
92
PrintTo(const RTCDataChannelStats & stats,::std::ostream * os)93 void PrintTo(const RTCDataChannelStats& stats, ::std::ostream* os) {
94 *os << stats.ToJson();
95 }
96
PrintTo(const RTCIceCandidatePairStats & stats,::std::ostream * os)97 void PrintTo(const RTCIceCandidatePairStats& stats, ::std::ostream* os) {
98 *os << stats.ToJson();
99 }
100
PrintTo(const RTCLocalIceCandidateStats & stats,::std::ostream * os)101 void PrintTo(const RTCLocalIceCandidateStats& stats, ::std::ostream* os) {
102 *os << stats.ToJson();
103 }
104
PrintTo(const RTCRemoteIceCandidateStats & stats,::std::ostream * os)105 void PrintTo(const RTCRemoteIceCandidateStats& stats, ::std::ostream* os) {
106 *os << stats.ToJson();
107 }
108
PrintTo(const RTCPeerConnectionStats & stats,::std::ostream * os)109 void PrintTo(const RTCPeerConnectionStats& stats, ::std::ostream* os) {
110 *os << stats.ToJson();
111 }
112
PrintTo(const DEPRECATED_RTCMediaStreamStats & stats,::std::ostream * os)113 void PrintTo(const DEPRECATED_RTCMediaStreamStats& stats, ::std::ostream* os) {
114 *os << stats.ToJson();
115 }
116
PrintTo(const DEPRECATED_RTCMediaStreamTrackStats & stats,::std::ostream * os)117 void PrintTo(const DEPRECATED_RTCMediaStreamTrackStats& stats,
118 ::std::ostream* os) {
119 *os << stats.ToJson();
120 }
121
PrintTo(const RTCInboundRTPStreamStats & stats,::std::ostream * os)122 void PrintTo(const RTCInboundRTPStreamStats& stats, ::std::ostream* os) {
123 *os << stats.ToJson();
124 }
125
PrintTo(const RTCOutboundRTPStreamStats & stats,::std::ostream * os)126 void PrintTo(const RTCOutboundRTPStreamStats& stats, ::std::ostream* os) {
127 *os << stats.ToJson();
128 }
129
PrintTo(const RTCRemoteInboundRtpStreamStats & stats,::std::ostream * os)130 void PrintTo(const RTCRemoteInboundRtpStreamStats& stats, ::std::ostream* os) {
131 *os << stats.ToJson();
132 }
133
PrintTo(const RTCAudioSourceStats & stats,::std::ostream * os)134 void PrintTo(const RTCAudioSourceStats& stats, ::std::ostream* os) {
135 *os << stats.ToJson();
136 }
137
PrintTo(const RTCVideoSourceStats & stats,::std::ostream * os)138 void PrintTo(const RTCVideoSourceStats& stats, ::std::ostream* os) {
139 *os << stats.ToJson();
140 }
141
PrintTo(const RTCTransportStats & stats,::std::ostream * os)142 void PrintTo(const RTCTransportStats& stats, ::std::ostream* os) {
143 *os << stats.ToJson();
144 }
145
146 namespace {
147
148 const int64_t kGetStatsReportTimeoutMs = 1000;
149
150 // Fake data used by `SetupExampleStatsVoiceGraph()` to fill in remote outbound
151 // stats.
152 constexpr int64_t kRemoteOutboundStatsTimestampMs = 123;
153 constexpr int64_t kRemoteOutboundStatsRemoteTimestampMs = 456;
154 constexpr uint32_t kRemoteOutboundStatsPacketsSent = 7u;
155 constexpr uint64_t kRemoteOutboundStatsBytesSent = 8u;
156 constexpr uint64_t kRemoteOutboundStatsReportsCount = 9u;
157
158 struct CertificateInfo {
159 rtc::scoped_refptr<rtc::RTCCertificate> certificate;
160 std::vector<std::string> ders;
161 std::vector<std::string> pems;
162 std::vector<std::string> fingerprints;
163 };
164
165 // Return the ID for an object of the given type in a report.
166 // The object must be present and be unique.
167 template <typename T>
IdForType(const RTCStatsReport * report)168 std::string IdForType(const RTCStatsReport* report) {
169 auto stats_of_my_type = report->RTCStatsReport::GetStatsOfType<T>();
170 // We cannot use ASSERT here, since we're within a function.
171 EXPECT_EQ(1U, stats_of_my_type.size())
172 << "Unexpected number of stats of this type";
173 if (stats_of_my_type.size() == 1) {
174 return stats_of_my_type[0]->id();
175 } else {
176 // Return something that is not going to be a valid stas ID.
177 return "Type not found";
178 }
179 }
180
CreateFakeCertificateAndInfoFromDers(const std::vector<std::string> & ders)181 std::unique_ptr<CertificateInfo> CreateFakeCertificateAndInfoFromDers(
182 const std::vector<std::string>& ders) {
183 RTC_CHECK(!ders.empty());
184 std::unique_ptr<CertificateInfo> info(new CertificateInfo());
185 info->ders = ders;
186 for (const std::string& der : ders) {
187 info->pems.push_back(rtc::SSLIdentity::DerToPem(
188 "CERTIFICATE", reinterpret_cast<const unsigned char*>(der.c_str()),
189 der.length()));
190 }
191 info->certificate =
192 rtc::RTCCertificate::Create(std::unique_ptr<rtc::FakeSSLIdentity>(
193 new rtc::FakeSSLIdentity(info->pems)));
194 // Strip header/footer and newline characters of PEM strings.
195 for (size_t i = 0; i < info->pems.size(); ++i) {
196 absl::StrReplaceAll({{"-----BEGIN CERTIFICATE-----", ""},
197 {"-----END CERTIFICATE-----", ""},
198 {"\n", ""}},
199 &info->pems[i]);
200 }
201 // Fingerprints for the whole certificate chain, starting with leaf
202 // certificate.
203 const rtc::SSLCertChain& chain = info->certificate->GetSSLCertificateChain();
204 std::unique_ptr<rtc::SSLFingerprint> fp;
205 for (size_t i = 0; i < chain.GetSize(); i++) {
206 fp = rtc::SSLFingerprint::Create("sha-1", chain.Get(i));
207 EXPECT_TRUE(fp);
208 info->fingerprints.push_back(fp->GetRfc4572Fingerprint());
209 }
210 EXPECT_EQ(info->ders.size(), info->fingerprints.size());
211 return info;
212 }
213
CreateFakeCandidate(const std::string & hostname,int port,const std::string & protocol,const rtc::AdapterType adapter_type,const std::string & candidate_type,uint32_t priority,const rtc::AdapterType underlying_type_for_vpn=rtc::ADAPTER_TYPE_UNKNOWN)214 std::unique_ptr<cricket::Candidate> CreateFakeCandidate(
215 const std::string& hostname,
216 int port,
217 const std::string& protocol,
218 const rtc::AdapterType adapter_type,
219 const std::string& candidate_type,
220 uint32_t priority,
221 const rtc::AdapterType underlying_type_for_vpn =
222 rtc::ADAPTER_TYPE_UNKNOWN) {
223 std::unique_ptr<cricket::Candidate> candidate(new cricket::Candidate());
224 candidate->set_address(rtc::SocketAddress(hostname, port));
225 candidate->set_protocol(protocol);
226 candidate->set_network_type(adapter_type);
227 candidate->set_underlying_type_for_vpn(underlying_type_for_vpn);
228 candidate->set_type(candidate_type);
229 candidate->set_priority(priority);
230 // Defaults for testing.
231 candidate->set_foundation("foundationIsAString");
232 candidate->set_username("iceusernamefragment");
233 return candidate;
234 }
235
236 class FakeAudioProcessor : public AudioProcessorInterface {
237 public:
FakeAudioProcessor()238 FakeAudioProcessor() {}
~FakeAudioProcessor()239 ~FakeAudioProcessor() {}
240
241 private:
GetStats(bool has_recv_streams)242 AudioProcessorInterface::AudioProcessorStatistics GetStats(
243 bool has_recv_streams) override {
244 AudioProcessorStatistics stats;
245 stats.apm_statistics.echo_return_loss = 2.0;
246 stats.apm_statistics.echo_return_loss_enhancement = 3.0;
247 return stats;
248 }
249 };
250
251 class FakeAudioTrackForStats : public MediaStreamTrack<AudioTrackInterface> {
252 public:
Create(const std::string & id,MediaStreamTrackInterface::TrackState state,bool create_fake_audio_processor)253 static rtc::scoped_refptr<FakeAudioTrackForStats> Create(
254 const std::string& id,
255 MediaStreamTrackInterface::TrackState state,
256 bool create_fake_audio_processor) {
257 auto audio_track_stats = rtc::make_ref_counted<FakeAudioTrackForStats>(id);
258 audio_track_stats->set_state(state);
259 if (create_fake_audio_processor) {
260 audio_track_stats->processor_ =
261 rtc::make_ref_counted<FakeAudioProcessor>();
262 }
263 return audio_track_stats;
264 }
265
FakeAudioTrackForStats(const std::string & id)266 explicit FakeAudioTrackForStats(const std::string& id)
267 : MediaStreamTrack<AudioTrackInterface>(id) {}
268
kind() const269 std::string kind() const override {
270 return MediaStreamTrackInterface::kAudioKind;
271 }
GetSource() const272 webrtc::AudioSourceInterface* GetSource() const override { return nullptr; }
AddSink(webrtc::AudioTrackSinkInterface * sink)273 void AddSink(webrtc::AudioTrackSinkInterface* sink) override {}
RemoveSink(webrtc::AudioTrackSinkInterface * sink)274 void RemoveSink(webrtc::AudioTrackSinkInterface* sink) override {}
GetSignalLevel(int * level)275 bool GetSignalLevel(int* level) override { return false; }
GetAudioProcessor()276 rtc::scoped_refptr<AudioProcessorInterface> GetAudioProcessor() override {
277 return processor_;
278 }
279
280 private:
281 rtc::scoped_refptr<FakeAudioProcessor> processor_;
282 };
283
284 class FakeVideoTrackSourceForStats : public VideoTrackSourceInterface {
285 public:
Create(int input_width,int input_height)286 static rtc::scoped_refptr<FakeVideoTrackSourceForStats> Create(
287 int input_width,
288 int input_height) {
289 return rtc::make_ref_counted<FakeVideoTrackSourceForStats>(input_width,
290 input_height);
291 }
292
FakeVideoTrackSourceForStats(int input_width,int input_height)293 FakeVideoTrackSourceForStats(int input_width, int input_height)
294 : input_width_(input_width), input_height_(input_height) {}
~FakeVideoTrackSourceForStats()295 ~FakeVideoTrackSourceForStats() override {}
296
297 // VideoTrackSourceInterface
is_screencast() const298 bool is_screencast() const override { return false; }
needs_denoising() const299 absl::optional<bool> needs_denoising() const override { return false; }
GetStats(VideoTrackSourceInterface::Stats * stats)300 bool GetStats(VideoTrackSourceInterface::Stats* stats) override {
301 stats->input_width = input_width_;
302 stats->input_height = input_height_;
303 return true;
304 }
305 // MediaSourceInterface (part of VideoTrackSourceInterface)
state() const306 MediaSourceInterface::SourceState state() const override {
307 return MediaSourceInterface::SourceState::kLive;
308 }
remote() const309 bool remote() const override { return false; }
310 // NotifierInterface (part of MediaSourceInterface)
RegisterObserver(ObserverInterface * observer)311 void RegisterObserver(ObserverInterface* observer) override {}
UnregisterObserver(ObserverInterface * observer)312 void UnregisterObserver(ObserverInterface* observer) override {}
313 // rtc::VideoSourceInterface<VideoFrame> (part of VideoTrackSourceInterface)
AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame> * sink,const rtc::VideoSinkWants & wants)314 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
315 const rtc::VideoSinkWants& wants) override {}
RemoveSink(rtc::VideoSinkInterface<VideoFrame> * sink)316 void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override {}
SupportsEncodedOutput() const317 bool SupportsEncodedOutput() const override { return false; }
GenerateKeyFrame()318 void GenerateKeyFrame() override {}
AddEncodedSink(rtc::VideoSinkInterface<RecordableEncodedFrame> * sink)319 void AddEncodedSink(
320 rtc::VideoSinkInterface<RecordableEncodedFrame>* sink) override {}
RemoveEncodedSink(rtc::VideoSinkInterface<RecordableEncodedFrame> * sink)321 void RemoveEncodedSink(
322 rtc::VideoSinkInterface<RecordableEncodedFrame>* sink) override {}
323
324 private:
325 int input_width_;
326 int input_height_;
327 };
328
329 class FakeVideoTrackForStats : public MediaStreamTrack<VideoTrackInterface> {
330 public:
Create(const std::string & id,MediaStreamTrackInterface::TrackState state,rtc::scoped_refptr<VideoTrackSourceInterface> source)331 static rtc::scoped_refptr<FakeVideoTrackForStats> Create(
332 const std::string& id,
333 MediaStreamTrackInterface::TrackState state,
334 rtc::scoped_refptr<VideoTrackSourceInterface> source) {
335 auto video_track =
336 rtc::make_ref_counted<FakeVideoTrackForStats>(id, std::move(source));
337 video_track->set_state(state);
338 return video_track;
339 }
340
FakeVideoTrackForStats(const std::string & id,rtc::scoped_refptr<VideoTrackSourceInterface> source)341 FakeVideoTrackForStats(const std::string& id,
342 rtc::scoped_refptr<VideoTrackSourceInterface> source)
343 : MediaStreamTrack<VideoTrackInterface>(id), source_(source) {}
344
kind() const345 std::string kind() const override {
346 return MediaStreamTrackInterface::kVideoKind;
347 }
348
AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame> * sink,const rtc::VideoSinkWants & wants)349 void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
350 const rtc::VideoSinkWants& wants) override {}
RemoveSink(rtc::VideoSinkInterface<VideoFrame> * sink)351 void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override {}
352
GetSource() const353 VideoTrackSourceInterface* GetSource() const override {
354 return source_.get();
355 }
356
357 private:
358 rtc::scoped_refptr<VideoTrackSourceInterface> source_;
359 };
360
CreateFakeTrack(cricket::MediaType media_type,const std::string & track_id,MediaStreamTrackInterface::TrackState track_state,bool create_fake_audio_processor=false)361 rtc::scoped_refptr<MediaStreamTrackInterface> CreateFakeTrack(
362 cricket::MediaType media_type,
363 const std::string& track_id,
364 MediaStreamTrackInterface::TrackState track_state,
365 bool create_fake_audio_processor = false) {
366 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
367 return FakeAudioTrackForStats::Create(track_id, track_state,
368 create_fake_audio_processor);
369 } else {
370 RTC_DCHECK_EQ(media_type, cricket::MEDIA_TYPE_VIDEO);
371 return FakeVideoTrackForStats::Create(track_id, track_state, nullptr);
372 }
373 }
374
CreateMockSender(cricket::MediaType media_type,rtc::scoped_refptr<MediaStreamTrackInterface> track,uint32_t ssrc,int attachment_id,std::vector<std::string> local_stream_ids)375 rtc::scoped_refptr<MockRtpSenderInternal> CreateMockSender(
376 cricket::MediaType media_type,
377 rtc::scoped_refptr<MediaStreamTrackInterface> track,
378 uint32_t ssrc,
379 int attachment_id,
380 std::vector<std::string> local_stream_ids) {
381 RTC_DCHECK(!track ||
382 (track->kind() == MediaStreamTrackInterface::kAudioKind &&
383 media_type == cricket::MEDIA_TYPE_AUDIO) ||
384 (track->kind() == MediaStreamTrackInterface::kVideoKind &&
385 media_type == cricket::MEDIA_TYPE_VIDEO));
386 auto sender = rtc::make_ref_counted<MockRtpSenderInternal>();
387 EXPECT_CALL(*sender, track()).WillRepeatedly(Return(track));
388 EXPECT_CALL(*sender, ssrc()).WillRepeatedly(Return(ssrc));
389 EXPECT_CALL(*sender, media_type()).WillRepeatedly(Return(media_type));
390 EXPECT_CALL(*sender, GetParameters()).WillRepeatedly(Invoke([ssrc]() {
391 RtpParameters params;
392 params.encodings.push_back(RtpEncodingParameters());
393 params.encodings[0].ssrc = ssrc;
394 return params;
395 }));
396 EXPECT_CALL(*sender, AttachmentId()).WillRepeatedly(Return(attachment_id));
397 EXPECT_CALL(*sender, stream_ids()).WillRepeatedly(Return(local_stream_ids));
398 EXPECT_CALL(*sender, SetTransceiverAsStopped());
399 return sender;
400 }
401
CreateMockReceiver(const rtc::scoped_refptr<MediaStreamTrackInterface> & track,uint32_t ssrc,int attachment_id)402 rtc::scoped_refptr<MockRtpReceiverInternal> CreateMockReceiver(
403 const rtc::scoped_refptr<MediaStreamTrackInterface>& track,
404 uint32_t ssrc,
405 int attachment_id) {
406 auto receiver = rtc::make_ref_counted<MockRtpReceiverInternal>();
407 EXPECT_CALL(*receiver, track()).WillRepeatedly(Return(track));
408 EXPECT_CALL(*receiver, streams())
409 .WillRepeatedly(
410 Return(std::vector<rtc::scoped_refptr<MediaStreamInterface>>({})));
411
412 EXPECT_CALL(*receiver, media_type())
413 .WillRepeatedly(
414 Return(track->kind() == MediaStreamTrackInterface::kAudioKind
415 ? cricket::MEDIA_TYPE_AUDIO
416 : cricket::MEDIA_TYPE_VIDEO));
417 EXPECT_CALL(*receiver, GetParameters()).WillRepeatedly(Invoke([ssrc]() {
418 RtpParameters params;
419 params.encodings.push_back(RtpEncodingParameters());
420 params.encodings[0].ssrc = ssrc;
421 return params;
422 }));
423 EXPECT_CALL(*receiver, AttachmentId()).WillRepeatedly(Return(attachment_id));
424 EXPECT_CALL(*receiver, Stop()).WillRepeatedly(Return());
425 return receiver;
426 }
427
428 class RTCStatsCollectorWrapper {
429 public:
RTCStatsCollectorWrapper(rtc::scoped_refptr<FakePeerConnectionForStats> pc)430 explicit RTCStatsCollectorWrapper(
431 rtc::scoped_refptr<FakePeerConnectionForStats> pc)
432 : pc_(pc),
433 stats_collector_(
434 RTCStatsCollector::Create(pc.get(),
435 50 * rtc::kNumMicrosecsPerMillisec)) {}
436
stats_collector()437 rtc::scoped_refptr<RTCStatsCollector> stats_collector() {
438 return stats_collector_;
439 }
440
GetStatsReport()441 rtc::scoped_refptr<const RTCStatsReport> GetStatsReport() {
442 rtc::scoped_refptr<RTCStatsObtainer> callback = RTCStatsObtainer::Create();
443 stats_collector_->GetStatsReport(callback);
444 return WaitForReport(callback);
445 }
446
GetStatsReportWithSenderSelector(rtc::scoped_refptr<RtpSenderInternal> selector)447 rtc::scoped_refptr<const RTCStatsReport> GetStatsReportWithSenderSelector(
448 rtc::scoped_refptr<RtpSenderInternal> selector) {
449 rtc::scoped_refptr<RTCStatsObtainer> callback = RTCStatsObtainer::Create();
450 stats_collector_->GetStatsReport(selector, callback);
451 return WaitForReport(callback);
452 }
453
GetStatsReportWithReceiverSelector(rtc::scoped_refptr<RtpReceiverInternal> selector)454 rtc::scoped_refptr<const RTCStatsReport> GetStatsReportWithReceiverSelector(
455 rtc::scoped_refptr<RtpReceiverInternal> selector) {
456 rtc::scoped_refptr<RTCStatsObtainer> callback = RTCStatsObtainer::Create();
457 stats_collector_->GetStatsReport(selector, callback);
458 return WaitForReport(callback);
459 }
460
GetFreshStatsReport()461 rtc::scoped_refptr<const RTCStatsReport> GetFreshStatsReport() {
462 stats_collector_->ClearCachedStatsReport();
463 return GetStatsReport();
464 }
465
SetupLocalTrackAndSender(cricket::MediaType media_type,const std::string & track_id,uint32_t ssrc,bool add_stream,int attachment_id)466 rtc::scoped_refptr<MockRtpSenderInternal> SetupLocalTrackAndSender(
467 cricket::MediaType media_type,
468 const std::string& track_id,
469 uint32_t ssrc,
470 bool add_stream,
471 int attachment_id) {
472 rtc::scoped_refptr<MediaStream> local_stream;
473 if (add_stream) {
474 local_stream = MediaStream::Create("LocalStreamId");
475 pc_->mutable_local_streams()->AddStream(local_stream);
476 }
477
478 rtc::scoped_refptr<MediaStreamTrackInterface> track;
479 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
480 track = CreateFakeTrack(media_type, track_id,
481 MediaStreamTrackInterface::kLive);
482 if (add_stream) {
483 local_stream->AddTrack(rtc::scoped_refptr<AudioTrackInterface>(
484 static_cast<AudioTrackInterface*>(track.get())));
485 }
486 } else {
487 track = CreateFakeTrack(media_type, track_id,
488 MediaStreamTrackInterface::kLive);
489 if (add_stream) {
490 local_stream->AddTrack(rtc::scoped_refptr<VideoTrackInterface>(
491 static_cast<VideoTrackInterface*>(track.get())));
492 }
493 }
494
495 rtc::scoped_refptr<MockRtpSenderInternal> sender =
496 CreateMockSender(media_type, track, ssrc, attachment_id, {});
497 EXPECT_CALL(*sender, Stop());
498 EXPECT_CALL(*sender, SetMediaChannel(_));
499 pc_->AddSender(sender);
500 return sender;
501 }
502
SetupRemoteTrackAndReceiver(cricket::MediaType media_type,const std::string & track_id,const std::string & stream_id,uint32_t ssrc)503 rtc::scoped_refptr<MockRtpReceiverInternal> SetupRemoteTrackAndReceiver(
504 cricket::MediaType media_type,
505 const std::string& track_id,
506 const std::string& stream_id,
507 uint32_t ssrc) {
508 rtc::scoped_refptr<MediaStream> remote_stream =
509 MediaStream::Create(stream_id);
510 pc_->mutable_remote_streams()->AddStream(remote_stream);
511
512 rtc::scoped_refptr<MediaStreamTrackInterface> track;
513 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
514 track = CreateFakeTrack(media_type, track_id,
515 MediaStreamTrackInterface::kLive);
516 remote_stream->AddTrack(rtc::scoped_refptr<AudioTrackInterface>(
517 static_cast<AudioTrackInterface*>(track.get())));
518 } else {
519 track = CreateFakeTrack(media_type, track_id,
520 MediaStreamTrackInterface::kLive);
521 remote_stream->AddTrack(rtc::scoped_refptr<VideoTrackInterface>(
522 static_cast<VideoTrackInterface*>(track.get())));
523 }
524
525 rtc::scoped_refptr<MockRtpReceiverInternal> receiver =
526 CreateMockReceiver(track, ssrc, 62);
527 EXPECT_CALL(*receiver, streams())
528 .WillRepeatedly(
529 Return(std::vector<rtc::scoped_refptr<MediaStreamInterface>>(
530 {remote_stream})));
531 EXPECT_CALL(*receiver, SetMediaChannel(_)).WillRepeatedly(Return());
532 pc_->AddReceiver(receiver);
533 return receiver;
534 }
535
536 // Attaches tracks to peer connections by configuring RTP senders and RTP
537 // receivers according to the tracks' pairings with
538 // |[Voice/Video][Sender/Receiver]Info| and their SSRCs. Local tracks can be
539 // associated with multiple |[Voice/Video]SenderInfo|s, remote tracks can only
540 // be associated with one |[Voice/Video]ReceiverInfo|.
541 // Senders get assigned attachment ID "ssrc + 10".
CreateMockRtpSendersReceiversAndChannels(std::initializer_list<std::pair<MediaStreamTrackInterface *,cricket::VoiceSenderInfo>> local_audio_track_info_pairs,std::initializer_list<std::pair<MediaStreamTrackInterface *,cricket::VoiceReceiverInfo>> remote_audio_track_info_pairs,std::initializer_list<std::pair<MediaStreamTrackInterface *,cricket::VideoSenderInfo>> local_video_track_info_pairs,std::initializer_list<std::pair<MediaStreamTrackInterface *,cricket::VideoReceiverInfo>> remote_video_track_info_pairs,std::vector<std::string> local_stream_ids,std::vector<rtc::scoped_refptr<MediaStreamInterface>> remote_streams)542 void CreateMockRtpSendersReceiversAndChannels(
543 std::initializer_list<
544 std::pair<MediaStreamTrackInterface*, cricket::VoiceSenderInfo>>
545 local_audio_track_info_pairs,
546 std::initializer_list<
547 std::pair<MediaStreamTrackInterface*, cricket::VoiceReceiverInfo>>
548 remote_audio_track_info_pairs,
549 std::initializer_list<
550 std::pair<MediaStreamTrackInterface*, cricket::VideoSenderInfo>>
551 local_video_track_info_pairs,
552 std::initializer_list<
553 std::pair<MediaStreamTrackInterface*, cricket::VideoReceiverInfo>>
554 remote_video_track_info_pairs,
555 std::vector<std::string> local_stream_ids,
556 std::vector<rtc::scoped_refptr<MediaStreamInterface>> remote_streams) {
557 cricket::VoiceMediaInfo voice_media_info;
558 cricket::VideoMediaInfo video_media_info;
559
560 // Local audio tracks and voice sender infos
561 for (auto& pair : local_audio_track_info_pairs) {
562 MediaStreamTrackInterface* local_audio_track = pair.first;
563 const cricket::VoiceSenderInfo& voice_sender_info = pair.second;
564 RTC_DCHECK_EQ(local_audio_track->kind(),
565 MediaStreamTrackInterface::kAudioKind);
566
567 voice_media_info.senders.push_back(voice_sender_info);
568 rtc::scoped_refptr<MockRtpSenderInternal> rtp_sender = CreateMockSender(
569 cricket::MEDIA_TYPE_AUDIO,
570 rtc::scoped_refptr<MediaStreamTrackInterface>(local_audio_track),
571 voice_sender_info.local_stats[0].ssrc,
572 voice_sender_info.local_stats[0].ssrc + 10, local_stream_ids);
573 EXPECT_CALL(*rtp_sender, SetMediaChannel(_)).WillRepeatedly(Return());
574 EXPECT_CALL(*rtp_sender, Stop());
575 pc_->AddSender(rtp_sender);
576 }
577
578 // Remote audio tracks and voice receiver infos
579 for (auto& pair : remote_audio_track_info_pairs) {
580 MediaStreamTrackInterface* remote_audio_track = pair.first;
581 const cricket::VoiceReceiverInfo& voice_receiver_info = pair.second;
582 RTC_DCHECK_EQ(remote_audio_track->kind(),
583 MediaStreamTrackInterface::kAudioKind);
584
585 voice_media_info.receivers.push_back(voice_receiver_info);
586 rtc::scoped_refptr<MockRtpReceiverInternal> rtp_receiver =
587 CreateMockReceiver(
588 rtc::scoped_refptr<MediaStreamTrackInterface>(remote_audio_track),
589 voice_receiver_info.local_stats[0].ssrc,
590 voice_receiver_info.local_stats[0].ssrc + 10);
591 EXPECT_CALL(*rtp_receiver, streams())
592 .WillRepeatedly(Return(remote_streams));
593 EXPECT_CALL(*rtp_receiver, SetMediaChannel(_)).WillRepeatedly(Return());
594 pc_->AddReceiver(rtp_receiver);
595 }
596
597 // Local video tracks and video sender infos
598 for (auto& pair : local_video_track_info_pairs) {
599 MediaStreamTrackInterface* local_video_track = pair.first;
600 const cricket::VideoSenderInfo& video_sender_info = pair.second;
601 RTC_DCHECK_EQ(local_video_track->kind(),
602 MediaStreamTrackInterface::kVideoKind);
603
604 video_media_info.senders.push_back(video_sender_info);
605 video_media_info.aggregated_senders.push_back(video_sender_info);
606 rtc::scoped_refptr<MockRtpSenderInternal> rtp_sender = CreateMockSender(
607 cricket::MEDIA_TYPE_VIDEO,
608 rtc::scoped_refptr<MediaStreamTrackInterface>(local_video_track),
609 video_sender_info.local_stats[0].ssrc,
610 video_sender_info.local_stats[0].ssrc + 10, local_stream_ids);
611 EXPECT_CALL(*rtp_sender, SetMediaChannel(_)).WillRepeatedly(Return());
612 EXPECT_CALL(*rtp_sender, Stop());
613 pc_->AddSender(rtp_sender);
614 }
615
616 // Remote video tracks and video receiver infos
617 for (auto& pair : remote_video_track_info_pairs) {
618 MediaStreamTrackInterface* remote_video_track = pair.first;
619 const cricket::VideoReceiverInfo& video_receiver_info = pair.second;
620 RTC_DCHECK_EQ(remote_video_track->kind(),
621 MediaStreamTrackInterface::kVideoKind);
622
623 video_media_info.receivers.push_back(video_receiver_info);
624 rtc::scoped_refptr<MockRtpReceiverInternal> rtp_receiver =
625 CreateMockReceiver(
626 rtc::scoped_refptr<MediaStreamTrackInterface>(remote_video_track),
627 video_receiver_info.local_stats[0].ssrc,
628 video_receiver_info.local_stats[0].ssrc + 10);
629 EXPECT_CALL(*rtp_receiver, streams())
630 .WillRepeatedly(Return(remote_streams));
631 EXPECT_CALL(*rtp_receiver, SetMediaChannel(_)).WillRepeatedly(Return());
632 pc_->AddReceiver(rtp_receiver);
633 }
634
635 pc_->AddVoiceChannel("audio", "transport", voice_media_info);
636 pc_->AddVideoChannel("video", "transport", video_media_info);
637 }
638
639 private:
WaitForReport(rtc::scoped_refptr<RTCStatsObtainer> callback)640 rtc::scoped_refptr<const RTCStatsReport> WaitForReport(
641 rtc::scoped_refptr<RTCStatsObtainer> callback) {
642 EXPECT_TRUE_WAIT(callback->report() != nullptr, kGetStatsReportTimeoutMs);
643 int64_t after = rtc::TimeUTCMicros();
644 for (const RTCStats& stats : *callback->report()) {
645 if (stats.type() == RTCRemoteInboundRtpStreamStats::kType ||
646 stats.type() == RTCRemoteOutboundRtpStreamStats::kType) {
647 // Ignore remote timestamps.
648 continue;
649 }
650 EXPECT_LE(stats.timestamp_us(), after);
651 }
652 return callback->report();
653 }
654
655 rtc::scoped_refptr<FakePeerConnectionForStats> pc_;
656 rtc::scoped_refptr<RTCStatsCollector> stats_collector_;
657 };
658
659 class RTCStatsCollectorTest : public ::testing::Test {
660 public:
RTCStatsCollectorTest()661 RTCStatsCollectorTest()
662 : pc_(rtc::make_ref_counted<FakePeerConnectionForStats>()),
663 stats_(new RTCStatsCollectorWrapper(pc_)) {}
664
ExpectReportContainsCertificateInfo(const rtc::scoped_refptr<const RTCStatsReport> & report,const CertificateInfo & certinfo)665 void ExpectReportContainsCertificateInfo(
666 const rtc::scoped_refptr<const RTCStatsReport>& report,
667 const CertificateInfo& certinfo) {
668 for (size_t i = 0; i < certinfo.fingerprints.size(); ++i) {
669 RTCCertificateStats expected_certificate_stats(
670 "CF" + certinfo.fingerprints[i], report->timestamp_us());
671 expected_certificate_stats.fingerprint = certinfo.fingerprints[i];
672 expected_certificate_stats.fingerprint_algorithm = "sha-1";
673 expected_certificate_stats.base64_certificate = certinfo.pems[i];
674 if (i + 1 < certinfo.fingerprints.size()) {
675 expected_certificate_stats.issuer_certificate_id =
676 "CF" + certinfo.fingerprints[i + 1];
677 }
678 ASSERT_TRUE(report->Get(expected_certificate_stats.id()));
679 EXPECT_EQ(expected_certificate_stats,
680 report->Get(expected_certificate_stats.id())
681 ->cast_to<RTCCertificateStats>());
682 }
683 }
684
GetCertificateStatsFromFingerprint(const rtc::scoped_refptr<const RTCStatsReport> & report,const std::string & fingerprint)685 const RTCCertificateStats* GetCertificateStatsFromFingerprint(
686 const rtc::scoped_refptr<const RTCStatsReport>& report,
687 const std::string& fingerprint) {
688 auto certificates = report->GetStatsOfType<RTCCertificateStats>();
689 for (const auto* certificate : certificates) {
690 if (*certificate->fingerprint == fingerprint) {
691 return certificate;
692 }
693 }
694 return nullptr;
695 }
696
697 struct ExampleStatsGraph {
698 rtc::scoped_refptr<RtpSenderInternal> sender;
699 rtc::scoped_refptr<RtpReceiverInternal> receiver;
700
701 rtc::scoped_refptr<const RTCStatsReport> full_report;
702 std::string send_codec_id;
703 std::string recv_codec_id;
704 std::string outbound_rtp_id;
705 std::string inbound_rtp_id;
706 std::string remote_outbound_rtp_id;
707 std::string transport_id;
708 std::string sender_track_id;
709 std::string receiver_track_id;
710 std::string remote_stream_id;
711 std::string peer_connection_id;
712 std::string media_source_id;
713 };
714
715 // Sets up the example stats graph (see ASCII art below) for a video only
716 // call. The graph is used for testing the stats selection algorithm (see
717 // https://w3c.github.io/webrtc-pc/#dfn-stats-selection-algorithm).
718 // These tests test the integration of the stats traversal algorithm inside of
719 // RTCStatsCollector. See rtcstatstraveral_unittest.cc for more stats
720 // traversal tests.
SetupExampleStatsGraphForSelectorTests()721 ExampleStatsGraph SetupExampleStatsGraphForSelectorTests() {
722 ExampleStatsGraph graph;
723
724 // codec (send)
725 graph.send_codec_id = "COTTransportName1_1";
726 cricket::VideoMediaInfo video_media_info;
727 RtpCodecParameters send_codec;
728 send_codec.payload_type = 1;
729 send_codec.clock_rate = 0;
730 video_media_info.send_codecs.insert(
731 std::make_pair(send_codec.payload_type, send_codec));
732 // codec (recv)
733 graph.recv_codec_id = "CITTransportName1_2";
734 RtpCodecParameters recv_codec;
735 recv_codec.payload_type = 2;
736 recv_codec.clock_rate = 0;
737 video_media_info.receive_codecs.insert(
738 std::make_pair(recv_codec.payload_type, recv_codec));
739 // outbound-rtp
740 graph.outbound_rtp_id = "OTTransportName1V3";
741 video_media_info.senders.push_back(cricket::VideoSenderInfo());
742 video_media_info.senders[0].local_stats.push_back(
743 cricket::SsrcSenderInfo());
744 video_media_info.senders[0].local_stats[0].ssrc = 3;
745 video_media_info.senders[0].codec_payload_type = send_codec.payload_type;
746 video_media_info.aggregated_senders.push_back(video_media_info.senders[0]);
747 // inbound-rtp
748 graph.inbound_rtp_id = "ITTransportName1V4";
749 video_media_info.receivers.push_back(cricket::VideoReceiverInfo());
750 video_media_info.receivers[0].local_stats.push_back(
751 cricket::SsrcReceiverInfo());
752 video_media_info.receivers[0].local_stats[0].ssrc = 4;
753 video_media_info.receivers[0].codec_payload_type = recv_codec.payload_type;
754 // transport
755 graph.transport_id = "TTransportName1";
756 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
757 // track (sender)
758 graph.sender = stats_->SetupLocalTrackAndSender(
759 cricket::MEDIA_TYPE_VIDEO, "LocalVideoTrackID", 3, false, 50);
760 graph.sender_track_id =
761 "DEPRECATED_TO" + rtc::ToString(graph.sender->AttachmentId());
762 // track (receiver) and stream (remote stream)
763 graph.receiver = stats_->SetupRemoteTrackAndReceiver(
764 cricket::MEDIA_TYPE_VIDEO, "RemoteVideoTrackID", "RemoteStreamId", 4);
765 graph.receiver_track_id =
766 "DEPRECATED_TI" + rtc::ToString(graph.receiver->AttachmentId());
767 graph.remote_stream_id = "DEPRECATED_SRemoteStreamId";
768 // peer-connection
769 graph.peer_connection_id = "P";
770 // media-source (kind: video)
771 graph.media_source_id = "SV" + rtc::ToString(graph.sender->AttachmentId());
772
773 // Expected stats graph:
774 //
775 // +--- track (sender) stream (remote stream) ---> track (receiver)
776 // | ^ ^
777 // | | |
778 // | +--------- outbound-rtp inbound-rtp ---------------+
779 // | | | | | |
780 // | | v v v v
781 // | | codec (send) transport codec (recv) peer-connection
782 // v v
783 // media-source
784
785 // Verify the stats graph is set up correctly.
786 graph.full_report = stats_->GetStatsReport();
787 EXPECT_EQ(graph.full_report->size(), 10u);
788 EXPECT_TRUE(graph.full_report->Get(graph.send_codec_id));
789 EXPECT_TRUE(graph.full_report->Get(graph.recv_codec_id));
790 EXPECT_TRUE(graph.full_report->Get(graph.outbound_rtp_id));
791 EXPECT_TRUE(graph.full_report->Get(graph.inbound_rtp_id));
792 EXPECT_TRUE(graph.full_report->Get(graph.transport_id));
793 EXPECT_TRUE(graph.full_report->Get(graph.sender_track_id));
794 EXPECT_TRUE(graph.full_report->Get(graph.receiver_track_id));
795 EXPECT_TRUE(graph.full_report->Get(graph.remote_stream_id));
796 EXPECT_TRUE(graph.full_report->Get(graph.peer_connection_id));
797 EXPECT_TRUE(graph.full_report->Get(graph.media_source_id));
798 const auto& sender_track =
799 graph.full_report->Get(graph.sender_track_id)
800 ->cast_to<DEPRECATED_RTCMediaStreamTrackStats>();
801 EXPECT_EQ(*sender_track.media_source_id, graph.media_source_id);
802 const auto& outbound_rtp = graph.full_report->Get(graph.outbound_rtp_id)
803 ->cast_to<RTCOutboundRTPStreamStats>();
804 EXPECT_EQ(*outbound_rtp.media_source_id, graph.media_source_id);
805 EXPECT_EQ(*outbound_rtp.codec_id, graph.send_codec_id);
806 EXPECT_EQ(*outbound_rtp.track_id, graph.sender_track_id);
807 EXPECT_EQ(*outbound_rtp.transport_id, graph.transport_id);
808 const auto& inbound_rtp = graph.full_report->Get(graph.inbound_rtp_id)
809 ->cast_to<RTCInboundRTPStreamStats>();
810 EXPECT_EQ(*inbound_rtp.codec_id, graph.recv_codec_id);
811 EXPECT_EQ(*inbound_rtp.track_id, graph.receiver_track_id);
812 EXPECT_EQ(*inbound_rtp.transport_id, graph.transport_id);
813
814 return graph;
815 }
816
817 // Sets up an example stats graph (see ASCII art below) for an audio only call
818 // and checks that the expected stats are generated.
SetupExampleStatsVoiceGraph(bool add_remote_outbound_stats)819 ExampleStatsGraph SetupExampleStatsVoiceGraph(
820 bool add_remote_outbound_stats) {
821 constexpr uint32_t kLocalSsrc = 3;
822 constexpr uint32_t kRemoteSsrc = 4;
823 ExampleStatsGraph graph;
824
825 // codec (send)
826 graph.send_codec_id = "COTTransportName1_1";
827 cricket::VoiceMediaInfo media_info;
828 RtpCodecParameters send_codec;
829 send_codec.payload_type = 1;
830 send_codec.clock_rate = 0;
831 media_info.send_codecs.insert(
832 std::make_pair(send_codec.payload_type, send_codec));
833 // codec (recv)
834 graph.recv_codec_id = "CITTransportName1_2";
835 RtpCodecParameters recv_codec;
836 recv_codec.payload_type = 2;
837 recv_codec.clock_rate = 0;
838 media_info.receive_codecs.insert(
839 std::make_pair(recv_codec.payload_type, recv_codec));
840 // outbound-rtp
841 graph.outbound_rtp_id = "OTTransportName1A3";
842 media_info.senders.push_back(cricket::VoiceSenderInfo());
843 media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
844 media_info.senders[0].local_stats[0].ssrc = kLocalSsrc;
845 media_info.senders[0].codec_payload_type = send_codec.payload_type;
846 // inbound-rtp
847 graph.inbound_rtp_id = "ITTransportName1A4";
848 media_info.receivers.push_back(cricket::VoiceReceiverInfo());
849 media_info.receivers[0].local_stats.push_back(cricket::SsrcReceiverInfo());
850 media_info.receivers[0].local_stats[0].ssrc = kRemoteSsrc;
851 media_info.receivers[0].codec_payload_type = recv_codec.payload_type;
852 // remote-outbound-rtp
853 if (add_remote_outbound_stats) {
854 graph.remote_outbound_rtp_id = "ROA4";
855 media_info.receivers[0].last_sender_report_timestamp_ms =
856 kRemoteOutboundStatsTimestampMs;
857 media_info.receivers[0].last_sender_report_remote_timestamp_ms =
858 kRemoteOutboundStatsRemoteTimestampMs;
859 media_info.receivers[0].sender_reports_packets_sent =
860 kRemoteOutboundStatsPacketsSent;
861 media_info.receivers[0].sender_reports_bytes_sent =
862 kRemoteOutboundStatsBytesSent;
863 media_info.receivers[0].sender_reports_reports_count =
864 kRemoteOutboundStatsReportsCount;
865 }
866
867 // transport
868 graph.transport_id = "TTransportName1";
869 pc_->AddVoiceChannel("VoiceMid", "TransportName", media_info);
870 // track (sender)
871 graph.sender = stats_->SetupLocalTrackAndSender(
872 cricket::MEDIA_TYPE_AUDIO, "LocalAudioTrackID", kLocalSsrc, false, 50);
873 graph.sender_track_id =
874 "DEPRECATED_TO" + rtc::ToString(graph.sender->AttachmentId());
875 // track (receiver) and stream (remote stream)
876 graph.receiver = stats_->SetupRemoteTrackAndReceiver(
877 cricket::MEDIA_TYPE_AUDIO, "RemoteAudioTrackID", "RemoteStreamId",
878 kRemoteSsrc);
879 graph.receiver_track_id =
880 "DEPRECATED_TI" + rtc::ToString(graph.receiver->AttachmentId());
881 graph.remote_stream_id = "DEPRECATED_SRemoteStreamId";
882 // peer-connection
883 graph.peer_connection_id = "P";
884 // media-source (kind: video)
885 graph.media_source_id = "SA" + rtc::ToString(graph.sender->AttachmentId());
886
887 // Expected stats graph:
888 //
889 // +--- track (sender) stream (remote stream) ---> track (receiver)
890 // | ^ ^
891 // | | |
892 // | +--------- outbound-rtp inbound-rtp ---------------+
893 // | | | | | |
894 // | | v v v v
895 // | | codec (send) transport codec (recv) peer-connection
896 // v v
897 // media-source
898
899 // Verify the stats graph is set up correctly.
900 graph.full_report = stats_->GetStatsReport();
901 EXPECT_EQ(graph.full_report->size(), add_remote_outbound_stats ? 11u : 10u);
902 EXPECT_TRUE(graph.full_report->Get(graph.send_codec_id));
903 EXPECT_TRUE(graph.full_report->Get(graph.recv_codec_id));
904 EXPECT_TRUE(graph.full_report->Get(graph.outbound_rtp_id));
905 EXPECT_TRUE(graph.full_report->Get(graph.inbound_rtp_id));
906 EXPECT_TRUE(graph.full_report->Get(graph.transport_id));
907 EXPECT_TRUE(graph.full_report->Get(graph.sender_track_id));
908 EXPECT_TRUE(graph.full_report->Get(graph.receiver_track_id));
909 EXPECT_TRUE(graph.full_report->Get(graph.remote_stream_id));
910 EXPECT_TRUE(graph.full_report->Get(graph.peer_connection_id));
911 EXPECT_TRUE(graph.full_report->Get(graph.media_source_id));
912 // `graph.remote_outbound_rtp_id` is omitted on purpose so that expectations
913 // can be added by the caller depending on what value it sets for the
914 // `add_remote_outbound_stats` argument.
915 const auto& sender_track =
916 graph.full_report->Get(graph.sender_track_id)
917 ->cast_to<DEPRECATED_RTCMediaStreamTrackStats>();
918 EXPECT_EQ(*sender_track.media_source_id, graph.media_source_id);
919 const auto& outbound_rtp = graph.full_report->Get(graph.outbound_rtp_id)
920 ->cast_to<RTCOutboundRTPStreamStats>();
921 EXPECT_EQ(*outbound_rtp.media_source_id, graph.media_source_id);
922 EXPECT_EQ(*outbound_rtp.codec_id, graph.send_codec_id);
923 EXPECT_EQ(*outbound_rtp.track_id, graph.sender_track_id);
924 EXPECT_EQ(*outbound_rtp.transport_id, graph.transport_id);
925 const auto& inbound_rtp = graph.full_report->Get(graph.inbound_rtp_id)
926 ->cast_to<RTCInboundRTPStreamStats>();
927 EXPECT_EQ(*inbound_rtp.codec_id, graph.recv_codec_id);
928 EXPECT_EQ(*inbound_rtp.track_id, graph.receiver_track_id);
929 EXPECT_EQ(*inbound_rtp.transport_id, graph.transport_id);
930
931 return graph;
932 }
933
934 protected:
935 rtc::ScopedFakeClock fake_clock_;
936 rtc::AutoThread main_thread_;
937 rtc::scoped_refptr<FakePeerConnectionForStats> pc_;
938 std::unique_ptr<RTCStatsCollectorWrapper> stats_;
939 };
940
TEST_F(RTCStatsCollectorTest,SingleCallback)941 TEST_F(RTCStatsCollectorTest, SingleCallback) {
942 rtc::scoped_refptr<const RTCStatsReport> result;
943 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&result));
944 EXPECT_TRUE_WAIT(result != nullptr, kGetStatsReportTimeoutMs);
945 }
946
TEST_F(RTCStatsCollectorTest,MultipleCallbacks)947 TEST_F(RTCStatsCollectorTest, MultipleCallbacks) {
948 rtc::scoped_refptr<const RTCStatsReport> a, b, c;
949 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&a));
950 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&b));
951 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&c));
952 EXPECT_TRUE_WAIT(a != nullptr, kGetStatsReportTimeoutMs);
953 EXPECT_TRUE_WAIT(b != nullptr, kGetStatsReportTimeoutMs);
954 EXPECT_TRUE_WAIT(c != nullptr, kGetStatsReportTimeoutMs);
955
956 EXPECT_EQ(a.get(), b.get());
957 EXPECT_EQ(b.get(), c.get());
958 }
959
TEST_F(RTCStatsCollectorTest,CachedStatsReports)960 TEST_F(RTCStatsCollectorTest, CachedStatsReports) {
961 // Caching should ensure `a` and `b` are the same report.
962 rtc::scoped_refptr<const RTCStatsReport> a = stats_->GetStatsReport();
963 rtc::scoped_refptr<const RTCStatsReport> b = stats_->GetStatsReport();
964 EXPECT_EQ(a.get(), b.get());
965 // Invalidate cache by clearing it.
966 stats_->stats_collector()->ClearCachedStatsReport();
967 rtc::scoped_refptr<const RTCStatsReport> c = stats_->GetStatsReport();
968 EXPECT_NE(b.get(), c.get());
969 // Invalidate cache by advancing time.
970 fake_clock_.AdvanceTime(TimeDelta::Millis(51));
971 rtc::scoped_refptr<const RTCStatsReport> d = stats_->GetStatsReport();
972 EXPECT_TRUE(d);
973 EXPECT_NE(c.get(), d.get());
974 }
975
TEST_F(RTCStatsCollectorTest,MultipleCallbacksWithInvalidatedCacheInBetween)976 TEST_F(RTCStatsCollectorTest, MultipleCallbacksWithInvalidatedCacheInBetween) {
977 rtc::scoped_refptr<const RTCStatsReport> a, b, c;
978 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&a));
979 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&b));
980 // Cache is invalidated after 50 ms.
981 fake_clock_.AdvanceTime(TimeDelta::Millis(51));
982 stats_->stats_collector()->GetStatsReport(RTCStatsObtainer::Create(&c));
983 EXPECT_TRUE_WAIT(a != nullptr, kGetStatsReportTimeoutMs);
984 EXPECT_TRUE_WAIT(b != nullptr, kGetStatsReportTimeoutMs);
985 EXPECT_TRUE_WAIT(c != nullptr, kGetStatsReportTimeoutMs);
986 EXPECT_EQ(a.get(), b.get());
987 // The act of doing `AdvanceTime` processes all messages. If this was not the
988 // case we might not require `c` to be fresher than `b`.
989 EXPECT_NE(c.get(), b.get());
990 }
991
TEST_F(RTCStatsCollectorTest,ToJsonProducesParseableJson)992 TEST_F(RTCStatsCollectorTest, ToJsonProducesParseableJson) {
993 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
994 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
995 std::string json_format = report->ToJson();
996
997 Json::CharReaderBuilder builder;
998 Json::Value json_value;
999 std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
1000 ASSERT_TRUE(reader->parse(json_format.c_str(),
1001 json_format.c_str() + json_format.size(),
1002 &json_value, nullptr));
1003
1004 // A very brief sanity check on the result.
1005 EXPECT_EQ(report->size(), json_value.size());
1006 }
1007
TEST_F(RTCStatsCollectorTest,CollectRTCCertificateStatsSingle)1008 TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsSingle) {
1009 const char kTransportName[] = "transport";
1010
1011 pc_->AddVoiceChannel("audio", kTransportName);
1012
1013 std::unique_ptr<CertificateInfo> local_certinfo =
1014 CreateFakeCertificateAndInfoFromDers(
1015 std::vector<std::string>({"(local) single certificate"}));
1016 pc_->SetLocalCertificate(kTransportName, local_certinfo->certificate);
1017
1018 std::unique_ptr<CertificateInfo> remote_certinfo =
1019 CreateFakeCertificateAndInfoFromDers(
1020 std::vector<std::string>({"(remote) single certificate"}));
1021 pc_->SetRemoteCertChain(
1022 kTransportName,
1023 remote_certinfo->certificate->GetSSLCertificateChain().Clone());
1024
1025 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1026
1027 ExpectReportContainsCertificateInfo(report, *local_certinfo);
1028 ExpectReportContainsCertificateInfo(report, *remote_certinfo);
1029 }
1030
1031 // These SSRC collisions are legal.
TEST_F(RTCStatsCollectorTest,ValidSsrcCollisionDoesNotCrash)1032 TEST_F(RTCStatsCollectorTest, ValidSsrcCollisionDoesNotCrash) {
1033 // BUNDLE audio/video inbound/outbound. Unique SSRCs needed within the BUNDLE.
1034 cricket::VoiceMediaInfo mid1_info;
1035 mid1_info.receivers.emplace_back();
1036 mid1_info.receivers[0].add_ssrc(1);
1037 mid1_info.senders.emplace_back();
1038 mid1_info.senders[0].add_ssrc(2);
1039 pc_->AddVoiceChannel("Mid1", "Transport1", mid1_info);
1040 cricket::VideoMediaInfo mid2_info;
1041 mid2_info.receivers.emplace_back();
1042 mid2_info.receivers[0].add_ssrc(3);
1043 mid2_info.senders.emplace_back();
1044 mid2_info.senders[0].add_ssrc(4);
1045 pc_->AddVideoChannel("Mid2", "Transport1", mid2_info);
1046 // Now create a second BUNDLE group with SSRCs colliding with the first group
1047 // (but again no collisions within the group).
1048 cricket::VoiceMediaInfo mid3_info;
1049 mid3_info.receivers.emplace_back();
1050 mid3_info.receivers[0].add_ssrc(1);
1051 mid3_info.senders.emplace_back();
1052 mid3_info.senders[0].add_ssrc(2);
1053 pc_->AddVoiceChannel("Mid3", "Transport2", mid3_info);
1054 cricket::VideoMediaInfo mid4_info;
1055 mid4_info.receivers.emplace_back();
1056 mid4_info.receivers[0].add_ssrc(3);
1057 mid4_info.senders.emplace_back();
1058 mid4_info.senders[0].add_ssrc(4);
1059 pc_->AddVideoChannel("Mid4", "Transport2", mid4_info);
1060
1061 // This should not crash (https://crbug.com/1361612).
1062 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1063 auto inbound_rtps = report->GetStatsOfType<RTCInboundRTPStreamStats>();
1064 auto outbound_rtps = report->GetStatsOfType<RTCOutboundRTPStreamStats>();
1065 EXPECT_EQ(inbound_rtps.size(), 4u);
1066 EXPECT_EQ(outbound_rtps.size(), 4u);
1067 }
1068
1069 // These SSRC collisions are illegal, so it is not clear if this setup can
1070 // happen even when talking to a malicious endpoint, but simulate illegal SSRC
1071 // collisions just to make sure we don't crash in even the most extreme cases.
TEST_F(RTCStatsCollectorTest,InvalidSsrcCollisionDoesNotCrash)1072 TEST_F(RTCStatsCollectorTest, InvalidSsrcCollisionDoesNotCrash) {
1073 // One SSRC to rule them all.
1074 cricket::VoiceMediaInfo mid1_info;
1075 mid1_info.receivers.emplace_back();
1076 mid1_info.receivers[0].add_ssrc(1);
1077 mid1_info.senders.emplace_back();
1078 mid1_info.senders[0].add_ssrc(1);
1079 pc_->AddVoiceChannel("Mid1", "BundledTransport", mid1_info);
1080 cricket::VideoMediaInfo mid2_info;
1081 mid2_info.receivers.emplace_back();
1082 mid2_info.receivers[0].add_ssrc(1);
1083 mid2_info.senders.emplace_back();
1084 mid2_info.senders[0].add_ssrc(1);
1085 pc_->AddVideoChannel("Mid2", "BundledTransport", mid2_info);
1086 cricket::VoiceMediaInfo mid3_info;
1087 mid3_info.receivers.emplace_back();
1088 mid3_info.receivers[0].add_ssrc(1);
1089 mid3_info.senders.emplace_back();
1090 mid3_info.senders[0].add_ssrc(1);
1091 pc_->AddVoiceChannel("Mid3", "BundledTransport", mid3_info);
1092 cricket::VideoMediaInfo mid4_info;
1093 mid4_info.receivers.emplace_back();
1094 mid4_info.receivers[0].add_ssrc(1);
1095 mid4_info.senders.emplace_back();
1096 mid4_info.senders[0].add_ssrc(1);
1097 pc_->AddVideoChannel("Mid4", "BundledTransport", mid4_info);
1098
1099 // This should not crash (https://crbug.com/1361612).
1100 stats_->GetStatsReport();
1101 // Because this setup is illegal, there is no "right answer" to how the report
1102 // should look. We only care about not crashing.
1103 }
1104
TEST_F(RTCStatsCollectorTest,CollectRTCCodecStatsOnlyIfReferenced)1105 TEST_F(RTCStatsCollectorTest, CollectRTCCodecStatsOnlyIfReferenced) {
1106 // Audio
1107 cricket::VoiceMediaInfo voice_media_info;
1108
1109 RtpCodecParameters inbound_audio_codec;
1110 inbound_audio_codec.payload_type = 1;
1111 inbound_audio_codec.kind = cricket::MEDIA_TYPE_AUDIO;
1112 inbound_audio_codec.name = "opus";
1113 inbound_audio_codec.clock_rate = 1337;
1114 inbound_audio_codec.num_channels = 1;
1115 inbound_audio_codec.parameters = {{"minptime", "10"}, {"useinbandfec", "1"}};
1116 voice_media_info.receive_codecs.insert(
1117 std::make_pair(inbound_audio_codec.payload_type, inbound_audio_codec));
1118
1119 RtpCodecParameters outbound_audio_codec;
1120 outbound_audio_codec.payload_type = 2;
1121 outbound_audio_codec.kind = cricket::MEDIA_TYPE_AUDIO;
1122 outbound_audio_codec.name = "isac";
1123 outbound_audio_codec.clock_rate = 1338;
1124 outbound_audio_codec.num_channels = 2;
1125 voice_media_info.send_codecs.insert(
1126 std::make_pair(outbound_audio_codec.payload_type, outbound_audio_codec));
1127
1128 // Video
1129 cricket::VideoMediaInfo video_media_info;
1130
1131 RtpCodecParameters inbound_video_codec;
1132 inbound_video_codec.payload_type = 3;
1133 inbound_video_codec.kind = cricket::MEDIA_TYPE_VIDEO;
1134 inbound_video_codec.name = "H264";
1135 inbound_video_codec.clock_rate = 1339;
1136 inbound_video_codec.parameters = {{"level-asymmetry-allowed", "1"},
1137 {"packetization-mode", "1"},
1138 {"profile-level-id", "42001f"}};
1139 video_media_info.receive_codecs.insert(
1140 std::make_pair(inbound_video_codec.payload_type, inbound_video_codec));
1141
1142 RtpCodecParameters outbound_video_codec;
1143 outbound_video_codec.payload_type = 4;
1144 outbound_video_codec.kind = cricket::MEDIA_TYPE_VIDEO;
1145 outbound_video_codec.name = "VP8";
1146 outbound_video_codec.clock_rate = 1340;
1147 video_media_info.send_codecs.insert(
1148 std::make_pair(outbound_video_codec.payload_type, outbound_video_codec));
1149
1150 // Ensure the above codecs are referenced.
1151 cricket::VoiceReceiverInfo inbound_audio_info;
1152 inbound_audio_info.add_ssrc(10);
1153 inbound_audio_info.codec_payload_type = 1;
1154 voice_media_info.receivers.push_back(inbound_audio_info);
1155
1156 cricket::VoiceSenderInfo outbound_audio_info;
1157 outbound_audio_info.add_ssrc(20);
1158 outbound_audio_info.codec_payload_type = 2;
1159 voice_media_info.senders.push_back(outbound_audio_info);
1160
1161 cricket::VideoReceiverInfo inbound_video_info;
1162 inbound_video_info.add_ssrc(30);
1163 inbound_video_info.codec_payload_type = 3;
1164 video_media_info.receivers.push_back(inbound_video_info);
1165
1166 cricket::VideoSenderInfo outbound_video_info;
1167 outbound_video_info.add_ssrc(40);
1168 outbound_video_info.codec_payload_type = 4;
1169 video_media_info.senders.push_back(outbound_video_info);
1170
1171 FakeVoiceMediaChannelForStats* audio_channel =
1172 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
1173 FakeVideoMediaChannelForStats* video_channel =
1174 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
1175
1176 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1177
1178 RTCCodecStats expected_inbound_audio_codec(
1179 "CITTransportName1_1_minptime=10;useinbandfec=1", report->timestamp_us());
1180 expected_inbound_audio_codec.payload_type = 1;
1181 expected_inbound_audio_codec.mime_type = "audio/opus";
1182 expected_inbound_audio_codec.clock_rate = 1337;
1183 expected_inbound_audio_codec.channels = 1;
1184 expected_inbound_audio_codec.sdp_fmtp_line = "minptime=10;useinbandfec=1";
1185 expected_inbound_audio_codec.transport_id = "TTransportName1";
1186
1187 RTCCodecStats expected_outbound_audio_codec("COTTransportName1_2",
1188 report->timestamp_us());
1189 expected_outbound_audio_codec.payload_type = 2;
1190 expected_outbound_audio_codec.mime_type = "audio/isac";
1191 expected_outbound_audio_codec.clock_rate = 1338;
1192 expected_outbound_audio_codec.channels = 2;
1193 expected_outbound_audio_codec.transport_id = "TTransportName1";
1194
1195 RTCCodecStats expected_inbound_video_codec(
1196 "CITTransportName1_3_level-asymmetry-allowed=1;"
1197 "packetization-mode=1;profile-level-id=42001f",
1198 report->timestamp_us());
1199 expected_inbound_video_codec.payload_type = 3;
1200 expected_inbound_video_codec.mime_type = "video/H264";
1201 expected_inbound_video_codec.clock_rate = 1339;
1202 expected_inbound_video_codec.sdp_fmtp_line =
1203 "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f";
1204 expected_inbound_video_codec.transport_id = "TTransportName1";
1205
1206 RTCCodecStats expected_outbound_video_codec("COTTransportName1_4",
1207 report->timestamp_us());
1208 expected_outbound_video_codec.payload_type = 4;
1209 expected_outbound_video_codec.mime_type = "video/VP8";
1210 expected_outbound_video_codec.clock_rate = 1340;
1211 expected_outbound_video_codec.transport_id = "TTransportName1";
1212
1213 ASSERT_TRUE(report->Get(expected_inbound_audio_codec.id()));
1214 EXPECT_EQ(
1215 expected_inbound_audio_codec,
1216 report->Get(expected_inbound_audio_codec.id())->cast_to<RTCCodecStats>());
1217
1218 ASSERT_TRUE(report->Get(expected_outbound_audio_codec.id()));
1219 EXPECT_EQ(expected_outbound_audio_codec,
1220 report->Get(expected_outbound_audio_codec.id())
1221 ->cast_to<RTCCodecStats>());
1222
1223 ASSERT_TRUE(report->Get(expected_inbound_video_codec.id()));
1224 EXPECT_EQ(
1225 expected_inbound_video_codec,
1226 report->Get(expected_inbound_video_codec.id())->cast_to<RTCCodecStats>());
1227
1228 ASSERT_TRUE(report->Get(expected_outbound_video_codec.id()));
1229 EXPECT_EQ(expected_outbound_video_codec,
1230 report->Get(expected_outbound_video_codec.id())
1231 ->cast_to<RTCCodecStats>());
1232
1233 // Now remove all the RTP streams such that there are no live codecId
1234 // references to the codecs, this should result in none of the RTCCodecStats
1235 // being exposed, despite `send_codecs` and `receive_codecs` still being set.
1236 voice_media_info.senders.clear();
1237 voice_media_info.receivers.clear();
1238 audio_channel->SetStats(voice_media_info);
1239 video_media_info.senders.clear();
1240 video_media_info.receivers.clear();
1241 video_channel->SetStats(video_media_info);
1242 stats_->stats_collector()->ClearCachedStatsReport();
1243 report = stats_->GetStatsReport();
1244 EXPECT_FALSE(report->Get(expected_inbound_audio_codec.id()));
1245 EXPECT_FALSE(report->Get(expected_outbound_audio_codec.id()));
1246 EXPECT_FALSE(report->Get(expected_inbound_video_codec.id()));
1247 EXPECT_FALSE(report->Get(expected_outbound_video_codec.id()));
1248 }
1249
TEST_F(RTCStatsCollectorTest,CodecStatsAreCollectedPerTransport)1250 TEST_F(RTCStatsCollectorTest, CodecStatsAreCollectedPerTransport) {
1251 // PT=10
1252 RtpCodecParameters outbound_codec_pt10;
1253 outbound_codec_pt10.payload_type = 10;
1254 outbound_codec_pt10.kind = cricket::MEDIA_TYPE_VIDEO;
1255 outbound_codec_pt10.name = "VP8";
1256 outbound_codec_pt10.clock_rate = 9000;
1257
1258 // PT=11
1259 RtpCodecParameters outbound_codec_pt11;
1260 outbound_codec_pt11.payload_type = 11;
1261 outbound_codec_pt11.kind = cricket::MEDIA_TYPE_VIDEO;
1262 outbound_codec_pt11.name = "VP8";
1263 outbound_codec_pt11.clock_rate = 9000;
1264
1265 // Insert codecs into `send_codecs` and ensure the PTs are referenced by RTP
1266 // streams.
1267 cricket::VideoMediaInfo info_pt10;
1268 info_pt10.send_codecs.insert(
1269 std::make_pair(outbound_codec_pt10.payload_type, outbound_codec_pt10));
1270 info_pt10.senders.emplace_back();
1271 info_pt10.senders[0].add_ssrc(42);
1272 info_pt10.senders[0].codec_payload_type = outbound_codec_pt10.payload_type;
1273
1274 cricket::VideoMediaInfo info_pt11;
1275 info_pt11.send_codecs.insert(
1276 std::make_pair(outbound_codec_pt11.payload_type, outbound_codec_pt11));
1277 info_pt11.senders.emplace_back();
1278 info_pt11.senders[0].add_ssrc(43);
1279 info_pt11.senders[0].codec_payload_type = outbound_codec_pt11.payload_type;
1280
1281 cricket::VideoMediaInfo info_pt10_pt11;
1282 info_pt10_pt11.send_codecs.insert(
1283 std::make_pair(outbound_codec_pt10.payload_type, outbound_codec_pt10));
1284 info_pt10_pt11.send_codecs.insert(
1285 std::make_pair(outbound_codec_pt11.payload_type, outbound_codec_pt11));
1286 info_pt10_pt11.senders.emplace_back();
1287 info_pt10_pt11.senders[0].add_ssrc(44);
1288 info_pt10_pt11.senders[0].codec_payload_type =
1289 outbound_codec_pt10.payload_type;
1290 info_pt10_pt11.senders.emplace_back();
1291 info_pt10_pt11.senders[1].add_ssrc(45);
1292 info_pt10_pt11.senders[1].codec_payload_type =
1293 outbound_codec_pt11.payload_type;
1294
1295 // First two mids contain subsets, the third one contains all PTs.
1296 pc_->AddVideoChannel("Mid1", "FirstTransport", info_pt10);
1297 pc_->AddVideoChannel("Mid2", "FirstTransport", info_pt11);
1298 pc_->AddVideoChannel("Mid3", "FirstTransport", info_pt10_pt11);
1299
1300 // There should be no duplicate codecs because all codec references are on the
1301 // same transport.
1302 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1303 auto codec_stats = report->GetStatsOfType<RTCCodecStats>();
1304 EXPECT_EQ(codec_stats.size(), 2u);
1305
1306 // If a second transport is added with the same PT information, this does
1307 // count as different codec objects.
1308 pc_->AddVideoChannel("Mid4", "SecondTransport", info_pt10_pt11);
1309 stats_->stats_collector()->ClearCachedStatsReport();
1310 report = stats_->GetStatsReport();
1311 codec_stats = report->GetStatsOfType<RTCCodecStats>();
1312 EXPECT_EQ(codec_stats.size(), 4u);
1313 }
1314
TEST_F(RTCStatsCollectorTest,SamePayloadTypeButDifferentFmtpLines)1315 TEST_F(RTCStatsCollectorTest, SamePayloadTypeButDifferentFmtpLines) {
1316 // PT=111, useinbandfec=0
1317 RtpCodecParameters inbound_codec_pt111_nofec;
1318 inbound_codec_pt111_nofec.payload_type = 111;
1319 inbound_codec_pt111_nofec.kind = cricket::MEDIA_TYPE_AUDIO;
1320 inbound_codec_pt111_nofec.name = "opus";
1321 inbound_codec_pt111_nofec.clock_rate = 48000;
1322 inbound_codec_pt111_nofec.parameters.insert(
1323 std::make_pair("useinbandfec", "0"));
1324
1325 // PT=111, useinbandfec=1
1326 RtpCodecParameters inbound_codec_pt111_fec;
1327 inbound_codec_pt111_fec.payload_type = 111;
1328 inbound_codec_pt111_fec.kind = cricket::MEDIA_TYPE_AUDIO;
1329 inbound_codec_pt111_fec.name = "opus";
1330 inbound_codec_pt111_fec.clock_rate = 48000;
1331 inbound_codec_pt111_fec.parameters.insert(
1332 std::make_pair("useinbandfec", "1"));
1333
1334 cricket::VideoMediaInfo info_nofec;
1335 info_nofec.receive_codecs.insert(std::make_pair(
1336 inbound_codec_pt111_nofec.payload_type, inbound_codec_pt111_nofec));
1337 info_nofec.receivers.emplace_back();
1338 info_nofec.receivers[0].add_ssrc(123);
1339 info_nofec.receivers[0].codec_payload_type =
1340 inbound_codec_pt111_nofec.payload_type;
1341 cricket::VideoMediaInfo info_fec;
1342 info_fec.receive_codecs.insert(std::make_pair(
1343 inbound_codec_pt111_fec.payload_type, inbound_codec_pt111_fec));
1344 info_fec.receivers.emplace_back();
1345 info_fec.receivers[0].add_ssrc(321);
1346 info_fec.receivers[0].codec_payload_type =
1347 inbound_codec_pt111_fec.payload_type;
1348
1349 // First two mids contain subsets, the third one contains all PTs.
1350 pc_->AddVideoChannel("Mid1", "BundledTransport", info_nofec);
1351 pc_->AddVideoChannel("Mid2", "BundledTransport", info_fec);
1352
1353 // Despite having the same PT we should see two codec stats because their FMTP
1354 // lines are different.
1355 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1356 auto codec_stats = report->GetStatsOfType<RTCCodecStats>();
1357 EXPECT_EQ(codec_stats.size(), 2u);
1358
1359 // Ensure SSRC uniqueness before the next AddVideoChannel() call. SSRCs need
1360 // to be unique on different m= sections when using BUNDLE.
1361 info_nofec.receivers[0].local_stats[0].ssrc = 12;
1362 info_fec.receivers[0].local_stats[0].ssrc = 21;
1363 // Adding more m= sections that does have the same FMTP lines does not result
1364 // in duplicates.
1365 pc_->AddVideoChannel("Mid3", "BundledTransport", info_nofec);
1366 pc_->AddVideoChannel("Mid4", "BundledTransport", info_fec);
1367 stats_->stats_collector()->ClearCachedStatsReport();
1368 report = stats_->GetStatsReport();
1369 codec_stats = report->GetStatsOfType<RTCCodecStats>();
1370 EXPECT_EQ(codec_stats.size(), 2u);
1371
1372 // Same FMTP line but a different PT does count as a new codec.
1373 // PT=112, useinbandfec=1
1374 RtpCodecParameters inbound_codec_pt112_fec;
1375 inbound_codec_pt112_fec.payload_type = 112;
1376 inbound_codec_pt112_fec.kind = cricket::MEDIA_TYPE_AUDIO;
1377 inbound_codec_pt112_fec.name = "opus";
1378 inbound_codec_pt112_fec.clock_rate = 48000;
1379 inbound_codec_pt112_fec.parameters.insert(
1380 std::make_pair("useinbandfec", "1"));
1381 cricket::VideoMediaInfo info_fec_pt112;
1382 info_fec_pt112.receive_codecs.insert(std::make_pair(
1383 inbound_codec_pt112_fec.payload_type, inbound_codec_pt112_fec));
1384 info_fec_pt112.receivers.emplace_back();
1385 info_fec_pt112.receivers[0].add_ssrc(112);
1386 info_fec_pt112.receivers[0].codec_payload_type =
1387 inbound_codec_pt112_fec.payload_type;
1388 pc_->AddVideoChannel("Mid5", "BundledTransport", info_fec_pt112);
1389 stats_->stats_collector()->ClearCachedStatsReport();
1390 report = stats_->GetStatsReport();
1391 codec_stats = report->GetStatsOfType<RTCCodecStats>();
1392 EXPECT_EQ(codec_stats.size(), 3u);
1393 }
1394
TEST_F(RTCStatsCollectorTest,CollectRTCCertificateStatsMultiple)1395 TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsMultiple) {
1396 const char kAudioTransport[] = "audio";
1397 const char kVideoTransport[] = "video";
1398
1399 pc_->AddVoiceChannel("audio", kAudioTransport);
1400
1401 std::unique_ptr<CertificateInfo> audio_local_certinfo =
1402 CreateFakeCertificateAndInfoFromDers(
1403 std::vector<std::string>({"(local) audio"}));
1404 pc_->SetLocalCertificate(kAudioTransport, audio_local_certinfo->certificate);
1405 std::unique_ptr<CertificateInfo> audio_remote_certinfo =
1406 CreateFakeCertificateAndInfoFromDers(
1407 std::vector<std::string>({"(remote) audio"}));
1408 pc_->SetRemoteCertChain(
1409 kAudioTransport,
1410 audio_remote_certinfo->certificate->GetSSLCertificateChain().Clone());
1411
1412 pc_->AddVideoChannel("video", kVideoTransport);
1413 std::unique_ptr<CertificateInfo> video_local_certinfo =
1414 CreateFakeCertificateAndInfoFromDers(
1415 std::vector<std::string>({"(local) video"}));
1416 pc_->SetLocalCertificate(kVideoTransport, video_local_certinfo->certificate);
1417 std::unique_ptr<CertificateInfo> video_remote_certinfo =
1418 CreateFakeCertificateAndInfoFromDers(
1419 std::vector<std::string>({"(remote) video"}));
1420 pc_->SetRemoteCertChain(
1421 kVideoTransport,
1422 video_remote_certinfo->certificate->GetSSLCertificateChain().Clone());
1423
1424 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1425 ExpectReportContainsCertificateInfo(report, *audio_local_certinfo);
1426 ExpectReportContainsCertificateInfo(report, *audio_remote_certinfo);
1427 ExpectReportContainsCertificateInfo(report, *video_local_certinfo);
1428 ExpectReportContainsCertificateInfo(report, *video_remote_certinfo);
1429 }
1430
TEST_F(RTCStatsCollectorTest,CollectRTCCertificateStatsChain)1431 TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsChain) {
1432 const char kTransportName[] = "transport";
1433
1434 pc_->AddVoiceChannel("audio", kTransportName);
1435
1436 std::unique_ptr<CertificateInfo> local_certinfo =
1437 CreateFakeCertificateAndInfoFromDers(
1438 {"(local) this", "(local) is", "(local) a", "(local) chain"});
1439 pc_->SetLocalCertificate(kTransportName, local_certinfo->certificate);
1440
1441 std::unique_ptr<CertificateInfo> remote_certinfo =
1442 CreateFakeCertificateAndInfoFromDers({"(remote) this", "(remote) is",
1443 "(remote) another",
1444 "(remote) chain"});
1445 pc_->SetRemoteCertChain(
1446 kTransportName,
1447 remote_certinfo->certificate->GetSSLCertificateChain().Clone());
1448
1449 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1450 ExpectReportContainsCertificateInfo(report, *local_certinfo);
1451 ExpectReportContainsCertificateInfo(report, *remote_certinfo);
1452 }
1453
TEST_F(RTCStatsCollectorTest,CertificateStatsCache)1454 TEST_F(RTCStatsCollectorTest, CertificateStatsCache) {
1455 const char kTransportName[] = "transport";
1456 rtc::ScopedFakeClock fake_clock;
1457
1458 pc_->AddVoiceChannel("audio", kTransportName);
1459
1460 // Set local and remote cerificates.
1461 std::unique_ptr<CertificateInfo> initial_local_certinfo =
1462 CreateFakeCertificateAndInfoFromDers({"LocalCertA", "LocalCertB"});
1463 pc_->SetLocalCertificate(kTransportName, initial_local_certinfo->certificate);
1464 std::unique_ptr<CertificateInfo> initial_remote_certinfo =
1465 CreateFakeCertificateAndInfoFromDers({"RemoteCertA", "RemoteCertB"});
1466 pc_->SetRemoteCertChain(
1467 kTransportName,
1468 initial_remote_certinfo->certificate->GetSSLCertificateChain().Clone());
1469 ASSERT_EQ(initial_local_certinfo->fingerprints.size(), 2u);
1470 ASSERT_EQ(initial_remote_certinfo->fingerprints.size(), 2u);
1471
1472 rtc::scoped_refptr<const RTCStatsReport> first_report =
1473 stats_->GetStatsReport();
1474 const auto* first_local_cert0 = GetCertificateStatsFromFingerprint(
1475 first_report, initial_local_certinfo->fingerprints[0]);
1476 const auto* first_local_cert1 = GetCertificateStatsFromFingerprint(
1477 first_report, initial_local_certinfo->fingerprints[1]);
1478 const auto* first_remote_cert0 = GetCertificateStatsFromFingerprint(
1479 first_report, initial_remote_certinfo->fingerprints[0]);
1480 const auto* first_remote_cert1 = GetCertificateStatsFromFingerprint(
1481 first_report, initial_remote_certinfo->fingerprints[1]);
1482 ASSERT_TRUE(first_local_cert0);
1483 ASSERT_TRUE(first_local_cert1);
1484 ASSERT_TRUE(first_remote_cert0);
1485 ASSERT_TRUE(first_remote_cert1);
1486 EXPECT_EQ(first_local_cert0->timestamp_us(), rtc::TimeMicros());
1487 EXPECT_EQ(first_local_cert1->timestamp_us(), rtc::TimeMicros());
1488 EXPECT_EQ(first_remote_cert0->timestamp_us(), rtc::TimeMicros());
1489 EXPECT_EQ(first_remote_cert1->timestamp_us(), rtc::TimeMicros());
1490
1491 // Replace all certificates.
1492 std::unique_ptr<CertificateInfo> updated_local_certinfo =
1493 CreateFakeCertificateAndInfoFromDers(
1494 {"UpdatedLocalCertA", "UpdatedLocalCertB"});
1495 pc_->SetLocalCertificate(kTransportName, updated_local_certinfo->certificate);
1496 std::unique_ptr<CertificateInfo> updated_remote_certinfo =
1497 CreateFakeCertificateAndInfoFromDers(
1498 {"UpdatedRemoteCertA", "UpdatedRemoteCertB"});
1499 pc_->SetRemoteCertChain(
1500 kTransportName,
1501 updated_remote_certinfo->certificate->GetSSLCertificateChain().Clone());
1502 // This test assumes fingerprints are different for the old and new
1503 // certificates.
1504 EXPECT_NE(initial_local_certinfo->fingerprints,
1505 updated_local_certinfo->fingerprints);
1506 EXPECT_NE(initial_remote_certinfo->fingerprints,
1507 updated_remote_certinfo->fingerprints);
1508
1509 // Advance time to ensure a fresh stats report, but don't clear the
1510 // certificate stats cache.
1511 fake_clock.AdvanceTime(TimeDelta::Seconds(1));
1512 rtc::scoped_refptr<const RTCStatsReport> second_report =
1513 stats_->GetStatsReport();
1514 // We expect to see the same certificates as before due to not clearing the
1515 // certificate cache.
1516 const auto* second_local_cert0 =
1517 second_report->GetAs<RTCCertificateStats>(first_local_cert0->id());
1518 const auto* second_local_cert1 =
1519 second_report->GetAs<RTCCertificateStats>(first_local_cert1->id());
1520 const auto* second_remote_cert0 =
1521 second_report->GetAs<RTCCertificateStats>(first_remote_cert0->id());
1522 const auto* second_remote_cert1 =
1523 second_report->GetAs<RTCCertificateStats>(first_remote_cert1->id());
1524 ASSERT_TRUE(second_local_cert0);
1525 ASSERT_TRUE(second_local_cert1);
1526 ASSERT_TRUE(second_remote_cert0);
1527 ASSERT_TRUE(second_remote_cert1);
1528 // The information in the certificate stats are obsolete.
1529 EXPECT_EQ(*second_local_cert0->fingerprint,
1530 initial_local_certinfo->fingerprints[0]);
1531 EXPECT_EQ(*second_local_cert1->fingerprint,
1532 initial_local_certinfo->fingerprints[1]);
1533 EXPECT_EQ(*second_remote_cert0->fingerprint,
1534 initial_remote_certinfo->fingerprints[0]);
1535 EXPECT_EQ(*second_remote_cert1->fingerprint,
1536 initial_remote_certinfo->fingerprints[1]);
1537 // But timestamps are up-to-date, because this is a fresh stats report.
1538 EXPECT_EQ(second_local_cert0->timestamp_us(), rtc::TimeMicros());
1539 EXPECT_EQ(second_local_cert1->timestamp_us(), rtc::TimeMicros());
1540 EXPECT_EQ(second_remote_cert0->timestamp_us(), rtc::TimeMicros());
1541 EXPECT_EQ(second_remote_cert1->timestamp_us(), rtc::TimeMicros());
1542 // The updated certificates are not part of the report yet.
1543 EXPECT_FALSE(GetCertificateStatsFromFingerprint(
1544 second_report, updated_local_certinfo->fingerprints[0]));
1545 EXPECT_FALSE(GetCertificateStatsFromFingerprint(
1546 second_report, updated_local_certinfo->fingerprints[1]));
1547 EXPECT_FALSE(GetCertificateStatsFromFingerprint(
1548 second_report, updated_remote_certinfo->fingerprints[0]));
1549 EXPECT_FALSE(GetCertificateStatsFromFingerprint(
1550 second_report, updated_remote_certinfo->fingerprints[1]));
1551
1552 // Clear the cache, including the cached certificates.
1553 stats_->stats_collector()->ClearCachedStatsReport();
1554 rtc::scoped_refptr<const RTCStatsReport> third_report =
1555 stats_->GetStatsReport();
1556 // Now the old certificates stats should be deleted.
1557 EXPECT_FALSE(third_report->Get(first_local_cert0->id()));
1558 EXPECT_FALSE(third_report->Get(first_local_cert1->id()));
1559 EXPECT_FALSE(third_report->Get(first_remote_cert0->id()));
1560 EXPECT_FALSE(third_report->Get(first_remote_cert1->id()));
1561 // And updated certificates exist.
1562 EXPECT_TRUE(GetCertificateStatsFromFingerprint(
1563 third_report, updated_local_certinfo->fingerprints[0]));
1564 EXPECT_TRUE(GetCertificateStatsFromFingerprint(
1565 third_report, updated_local_certinfo->fingerprints[1]));
1566 EXPECT_TRUE(GetCertificateStatsFromFingerprint(
1567 third_report, updated_remote_certinfo->fingerprints[0]));
1568 EXPECT_TRUE(GetCertificateStatsFromFingerprint(
1569 third_report, updated_remote_certinfo->fingerprints[1]));
1570 }
1571
TEST_F(RTCStatsCollectorTest,CollectTwoRTCDataChannelStatsWithPendingId)1572 TEST_F(RTCStatsCollectorTest, CollectTwoRTCDataChannelStatsWithPendingId) {
1573 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
1574 /*id=*/-1, DataChannelInterface::kConnecting));
1575 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
1576 /*id=*/-1, DataChannelInterface::kConnecting));
1577
1578 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1579 }
1580
TEST_F(RTCStatsCollectorTest,CollectRTCDataChannelStats)1581 TEST_F(RTCStatsCollectorTest, CollectRTCDataChannelStats) {
1582 // Note: The test assumes data channel IDs are predictable.
1583 // This is not a safe assumption, but in order to make it work for
1584 // the test, we reset the ID allocator at test start.
1585 SctpDataChannel::ResetInternalIdAllocatorForTesting(-1);
1586 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
1587 0, "MockSctpDataChannel0", DataChannelInterface::kConnecting, "udp", 1, 2,
1588 3, 4));
1589 RTCDataChannelStats expected_data_channel0("D0", 0);
1590 expected_data_channel0.label = "MockSctpDataChannel0";
1591 expected_data_channel0.protocol = "udp";
1592 expected_data_channel0.data_channel_identifier = 0;
1593 expected_data_channel0.state = "connecting";
1594 expected_data_channel0.messages_sent = 1;
1595 expected_data_channel0.bytes_sent = 2;
1596 expected_data_channel0.messages_received = 3;
1597 expected_data_channel0.bytes_received = 4;
1598
1599 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
1600 1, "MockSctpDataChannel1", DataChannelInterface::kOpen, "tcp", 5, 6, 7,
1601 8));
1602 RTCDataChannelStats expected_data_channel1("D1", 0);
1603 expected_data_channel1.label = "MockSctpDataChannel1";
1604 expected_data_channel1.protocol = "tcp";
1605 expected_data_channel1.data_channel_identifier = 1;
1606 expected_data_channel1.state = "open";
1607 expected_data_channel1.messages_sent = 5;
1608 expected_data_channel1.bytes_sent = 6;
1609 expected_data_channel1.messages_received = 7;
1610 expected_data_channel1.bytes_received = 8;
1611
1612 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
1613 2, "MockSctpDataChannel2", DataChannelInterface::kClosing, "udp", 9, 10,
1614 11, 12));
1615 RTCDataChannelStats expected_data_channel2("D2", 0);
1616 expected_data_channel2.label = "MockSctpDataChannel2";
1617 expected_data_channel2.protocol = "udp";
1618 expected_data_channel2.data_channel_identifier = 2;
1619 expected_data_channel2.state = "closing";
1620 expected_data_channel2.messages_sent = 9;
1621 expected_data_channel2.bytes_sent = 10;
1622 expected_data_channel2.messages_received = 11;
1623 expected_data_channel2.bytes_received = 12;
1624
1625 pc_->AddSctpDataChannel(rtc::make_ref_counted<MockSctpDataChannel>(
1626 3, "MockSctpDataChannel3", DataChannelInterface::kClosed, "tcp", 13, 14,
1627 15, 16));
1628 RTCDataChannelStats expected_data_channel3("D3", 0);
1629 expected_data_channel3.label = "MockSctpDataChannel3";
1630 expected_data_channel3.protocol = "tcp";
1631 expected_data_channel3.data_channel_identifier = 3;
1632 expected_data_channel3.state = "closed";
1633 expected_data_channel3.messages_sent = 13;
1634 expected_data_channel3.bytes_sent = 14;
1635 expected_data_channel3.messages_received = 15;
1636 expected_data_channel3.bytes_received = 16;
1637
1638 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1639
1640 ASSERT_TRUE(report->Get(expected_data_channel0.id()));
1641 EXPECT_EQ(
1642 expected_data_channel0,
1643 report->Get(expected_data_channel0.id())->cast_to<RTCDataChannelStats>());
1644 ASSERT_TRUE(report->Get(expected_data_channel1.id()));
1645 EXPECT_EQ(
1646 expected_data_channel1,
1647 report->Get(expected_data_channel1.id())->cast_to<RTCDataChannelStats>());
1648 ASSERT_TRUE(report->Get(expected_data_channel2.id()));
1649 EXPECT_EQ(
1650 expected_data_channel2,
1651 report->Get(expected_data_channel2.id())->cast_to<RTCDataChannelStats>());
1652 ASSERT_TRUE(report->Get(expected_data_channel3.id()));
1653 EXPECT_EQ(
1654 expected_data_channel3,
1655 report->Get(expected_data_channel3.id())->cast_to<RTCDataChannelStats>());
1656 }
1657
TEST_F(RTCStatsCollectorTest,CollectRTCIceCandidateStats)1658 TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidateStats) {
1659 // Candidates in the first transport stats.
1660 std::unique_ptr<cricket::Candidate> a_local_host = CreateFakeCandidate(
1661 "1.2.3.4", 5, "a_local_host's protocol", rtc::ADAPTER_TYPE_VPN,
1662 cricket::LOCAL_PORT_TYPE, 0, rtc::ADAPTER_TYPE_ETHERNET);
1663 RTCLocalIceCandidateStats expected_a_local_host("I" + a_local_host->id(), 0);
1664 expected_a_local_host.transport_id = "Ta0";
1665 expected_a_local_host.network_type = "vpn";
1666 expected_a_local_host.ip = "1.2.3.4";
1667 expected_a_local_host.address = "1.2.3.4";
1668 expected_a_local_host.port = 5;
1669 expected_a_local_host.protocol = "a_local_host's protocol";
1670 expected_a_local_host.candidate_type = "host";
1671 expected_a_local_host.priority = 0;
1672 expected_a_local_host.vpn = true;
1673 expected_a_local_host.network_adapter_type = RTCNetworkAdapterType::kEthernet;
1674 expected_a_local_host.foundation = "foundationIsAString";
1675 expected_a_local_host.username_fragment = "iceusernamefragment";
1676
1677 std::unique_ptr<cricket::Candidate> a_remote_srflx = CreateFakeCandidate(
1678 "6.7.8.9", 10, "remote_srflx's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
1679 cricket::STUN_PORT_TYPE, 1);
1680 RTCRemoteIceCandidateStats expected_a_remote_srflx("I" + a_remote_srflx->id(),
1681 0);
1682 expected_a_remote_srflx.transport_id = "Ta0";
1683 expected_a_remote_srflx.ip = "6.7.8.9";
1684 expected_a_remote_srflx.address = "6.7.8.9";
1685 expected_a_remote_srflx.port = 10;
1686 expected_a_remote_srflx.protocol = "remote_srflx's protocol";
1687 expected_a_remote_srflx.candidate_type = "srflx";
1688 expected_a_remote_srflx.priority = 1;
1689 expected_a_remote_srflx.foundation = "foundationIsAString";
1690 expected_a_remote_srflx.username_fragment = "iceusernamefragment";
1691
1692 std::unique_ptr<cricket::Candidate> a_local_prflx = CreateFakeCandidate(
1693 "11.12.13.14", 15, "a_local_prflx's protocol",
1694 rtc::ADAPTER_TYPE_CELLULAR_2G, cricket::PRFLX_PORT_TYPE, 2);
1695 RTCLocalIceCandidateStats expected_a_local_prflx("I" + a_local_prflx->id(),
1696 0);
1697 expected_a_local_prflx.transport_id = "Ta0";
1698 expected_a_local_prflx.network_type = "cellular";
1699 expected_a_local_prflx.ip = "11.12.13.14";
1700 expected_a_local_prflx.address = "11.12.13.14";
1701 expected_a_local_prflx.port = 15;
1702 expected_a_local_prflx.protocol = "a_local_prflx's protocol";
1703 expected_a_local_prflx.candidate_type = "prflx";
1704 expected_a_local_prflx.priority = 2;
1705 expected_a_local_prflx.vpn = false;
1706 expected_a_local_prflx.network_adapter_type =
1707 RTCNetworkAdapterType::kCellular2g;
1708 expected_a_local_prflx.foundation = "foundationIsAString";
1709 expected_a_local_prflx.username_fragment = "iceusernamefragment";
1710
1711 std::unique_ptr<cricket::Candidate> a_remote_relay = CreateFakeCandidate(
1712 "16.17.18.19", 20, "a_remote_relay's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
1713 cricket::RELAY_PORT_TYPE, 3);
1714 RTCRemoteIceCandidateStats expected_a_remote_relay("I" + a_remote_relay->id(),
1715 0);
1716 expected_a_remote_relay.transport_id = "Ta0";
1717 expected_a_remote_relay.ip = "16.17.18.19";
1718 expected_a_remote_relay.address = "16.17.18.19";
1719 expected_a_remote_relay.port = 20;
1720 expected_a_remote_relay.protocol = "a_remote_relay's protocol";
1721 expected_a_remote_relay.candidate_type = "relay";
1722 expected_a_remote_relay.priority = 3;
1723 expected_a_remote_relay.foundation = "foundationIsAString";
1724 expected_a_remote_relay.username_fragment = "iceusernamefragment";
1725
1726 std::unique_ptr<cricket::Candidate> a_local_relay = CreateFakeCandidate(
1727 "16.17.18.19", 21, "a_local_relay's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
1728 cricket::RELAY_PORT_TYPE, 1);
1729 a_local_relay->set_relay_protocol("tcp");
1730 a_local_relay->set_url("turn:url1");
1731
1732 RTCLocalIceCandidateStats expected_a_local_relay("I" + a_local_relay->id(),
1733 0);
1734 expected_a_local_relay.transport_id = "Ta0";
1735 expected_a_local_relay.network_type = "unknown";
1736 expected_a_local_relay.ip = "16.17.18.19";
1737 expected_a_local_relay.address = "16.17.18.19";
1738 expected_a_local_relay.port = 21;
1739 expected_a_local_relay.protocol = "a_local_relay's protocol";
1740 expected_a_local_relay.relay_protocol = "tcp";
1741 expected_a_local_relay.candidate_type = "relay";
1742 expected_a_local_relay.priority = 1;
1743 expected_a_local_relay.url = "turn:url1";
1744 expected_a_local_relay.vpn = false;
1745 expected_a_local_relay.network_adapter_type = RTCNetworkAdapterType::kUnknown;
1746 expected_a_local_relay.foundation = "foundationIsAString";
1747 expected_a_local_relay.username_fragment = "iceusernamefragment";
1748
1749 std::unique_ptr<cricket::Candidate> a_local_relay_prflx = CreateFakeCandidate(
1750 "11.12.13.20", 22, "a_local_relay_prflx's protocol",
1751 rtc::ADAPTER_TYPE_UNKNOWN, cricket::PRFLX_PORT_TYPE, 1);
1752 a_local_relay_prflx->set_relay_protocol("udp");
1753
1754 RTCLocalIceCandidateStats expected_a_local_relay_prflx(
1755 "I" + a_local_relay_prflx->id(), 0);
1756 expected_a_local_relay_prflx.transport_id = "Ta0";
1757 expected_a_local_relay_prflx.network_type = "unknown";
1758 expected_a_local_relay_prflx.ip = "11.12.13.20";
1759 expected_a_local_relay_prflx.address = "11.12.13.20";
1760 expected_a_local_relay_prflx.port = 22;
1761 expected_a_local_relay_prflx.protocol = "a_local_relay_prflx's protocol";
1762 expected_a_local_relay_prflx.relay_protocol = "udp";
1763 expected_a_local_relay_prflx.candidate_type = "prflx";
1764 expected_a_local_relay_prflx.priority = 1;
1765 expected_a_local_relay_prflx.vpn = false;
1766 expected_a_local_relay_prflx.network_adapter_type =
1767 RTCNetworkAdapterType::kUnknown;
1768 expected_a_local_relay_prflx.foundation = "foundationIsAString";
1769 expected_a_local_relay_prflx.username_fragment = "iceusernamefragment";
1770
1771 // A non-paired local candidate.
1772 std::unique_ptr<cricket::Candidate> a_local_host_not_paired =
1773 CreateFakeCandidate("1.2.3.4", 4404, "a_local_host_not_paired's protocol",
1774 rtc::ADAPTER_TYPE_VPN, cricket::LOCAL_PORT_TYPE, 0,
1775 rtc::ADAPTER_TYPE_ETHERNET);
1776 RTCLocalIceCandidateStats expected_a_local_host_not_paired(
1777 "I" + a_local_host_not_paired->id(), 0);
1778 expected_a_local_host_not_paired.transport_id = "Ta0";
1779 expected_a_local_host_not_paired.network_type = "vpn";
1780 expected_a_local_host_not_paired.ip = "1.2.3.4";
1781 expected_a_local_host_not_paired.address = "1.2.3.4";
1782 expected_a_local_host_not_paired.port = 4404;
1783 expected_a_local_host_not_paired.protocol =
1784 "a_local_host_not_paired's protocol";
1785 expected_a_local_host_not_paired.candidate_type = "host";
1786 expected_a_local_host_not_paired.priority = 0;
1787 expected_a_local_host_not_paired.vpn = true;
1788 expected_a_local_host_not_paired.network_adapter_type =
1789 RTCNetworkAdapterType::kEthernet;
1790 expected_a_local_host_not_paired.foundation = "foundationIsAString";
1791 expected_a_local_host_not_paired.username_fragment = "iceusernamefragment";
1792
1793 // Candidates in the second transport stats.
1794 std::unique_ptr<cricket::Candidate> b_local =
1795 CreateFakeCandidate("42.42.42.42", 42, "b_local's protocol",
1796 rtc::ADAPTER_TYPE_WIFI, cricket::LOCAL_PORT_TYPE, 42);
1797 RTCLocalIceCandidateStats expected_b_local("I" + b_local->id(), 0);
1798 expected_b_local.transport_id = "Tb0";
1799 expected_b_local.network_type = "wifi";
1800 expected_b_local.ip = "42.42.42.42";
1801 expected_b_local.address = "42.42.42.42";
1802 expected_b_local.port = 42;
1803 expected_b_local.protocol = "b_local's protocol";
1804 expected_b_local.candidate_type = "host";
1805 expected_b_local.priority = 42;
1806 expected_b_local.vpn = false;
1807 expected_b_local.network_adapter_type = RTCNetworkAdapterType::kWifi;
1808 expected_b_local.foundation = "foundationIsAString";
1809 expected_b_local.username_fragment = "iceusernamefragment";
1810
1811 std::unique_ptr<cricket::Candidate> b_remote = CreateFakeCandidate(
1812 "42.42.42.42", 42, "b_remote's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
1813 cricket::LOCAL_PORT_TYPE, 42);
1814 RTCRemoteIceCandidateStats expected_b_remote("I" + b_remote->id(), 0);
1815 expected_b_remote.transport_id = "Tb0";
1816 expected_b_remote.ip = "42.42.42.42";
1817 expected_b_remote.address = "42.42.42.42";
1818 expected_b_remote.port = 42;
1819 expected_b_remote.protocol = "b_remote's protocol";
1820 expected_b_remote.candidate_type = "host";
1821 expected_b_remote.priority = 42;
1822 expected_b_remote.foundation = "foundationIsAString";
1823 expected_b_remote.username_fragment = "iceusernamefragment";
1824
1825 // Add candidate pairs to connection.
1826 cricket::TransportChannelStats a_transport_channel_stats;
1827 a_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
1828 cricket::ConnectionInfo());
1829 a_transport_channel_stats.ice_transport_stats.connection_infos[0]
1830 .local_candidate = *a_local_host.get();
1831 a_transport_channel_stats.ice_transport_stats.connection_infos[0]
1832 .remote_candidate = *a_remote_srflx.get();
1833 a_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
1834 cricket::ConnectionInfo());
1835 a_transport_channel_stats.ice_transport_stats.connection_infos[1]
1836 .local_candidate = *a_local_prflx.get();
1837 a_transport_channel_stats.ice_transport_stats.connection_infos[1]
1838 .remote_candidate = *a_remote_relay.get();
1839 a_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
1840 cricket::ConnectionInfo());
1841 a_transport_channel_stats.ice_transport_stats.connection_infos[2]
1842 .local_candidate = *a_local_relay.get();
1843 a_transport_channel_stats.ice_transport_stats.connection_infos[2]
1844 .remote_candidate = *a_remote_relay.get();
1845 a_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
1846 cricket::ConnectionInfo());
1847 a_transport_channel_stats.ice_transport_stats.connection_infos[3]
1848 .local_candidate = *a_local_relay_prflx.get();
1849 a_transport_channel_stats.ice_transport_stats.connection_infos[3]
1850 .remote_candidate = *a_remote_relay.get();
1851 a_transport_channel_stats.ice_transport_stats.candidate_stats_list.push_back(
1852 cricket::CandidateStats(*a_local_host_not_paired.get()));
1853
1854 pc_->AddVoiceChannel("audio", "a");
1855 pc_->SetTransportStats("a", a_transport_channel_stats);
1856
1857 cricket::TransportChannelStats b_transport_channel_stats;
1858 b_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
1859 cricket::ConnectionInfo());
1860 b_transport_channel_stats.ice_transport_stats.connection_infos[0]
1861 .local_candidate = *b_local.get();
1862 b_transport_channel_stats.ice_transport_stats.connection_infos[0]
1863 .remote_candidate = *b_remote.get();
1864
1865 pc_->AddVideoChannel("video", "b");
1866 pc_->SetTransportStats("b", b_transport_channel_stats);
1867
1868 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1869
1870 ASSERT_TRUE(report->Get(expected_a_local_host.id()));
1871 EXPECT_EQ(expected_a_local_host, report->Get(expected_a_local_host.id())
1872 ->cast_to<RTCLocalIceCandidateStats>());
1873
1874 ASSERT_TRUE(report->Get(expected_a_local_host_not_paired.id()));
1875 EXPECT_EQ(expected_a_local_host_not_paired,
1876 report->Get(expected_a_local_host_not_paired.id())
1877 ->cast_to<RTCLocalIceCandidateStats>());
1878
1879 ASSERT_TRUE(report->Get(expected_a_remote_srflx.id()));
1880 EXPECT_EQ(expected_a_remote_srflx,
1881 report->Get(expected_a_remote_srflx.id())
1882 ->cast_to<RTCRemoteIceCandidateStats>());
1883 ASSERT_TRUE(report->Get(expected_a_local_prflx.id()));
1884 EXPECT_EQ(expected_a_local_prflx, report->Get(expected_a_local_prflx.id())
1885 ->cast_to<RTCLocalIceCandidateStats>());
1886 ASSERT_TRUE(report->Get(expected_a_remote_relay.id()));
1887 EXPECT_EQ(expected_a_remote_relay,
1888 report->Get(expected_a_remote_relay.id())
1889 ->cast_to<RTCRemoteIceCandidateStats>());
1890 ASSERT_TRUE(report->Get(expected_a_local_relay.id()));
1891 EXPECT_EQ(expected_a_local_relay, report->Get(expected_a_local_relay.id())
1892 ->cast_to<RTCLocalIceCandidateStats>());
1893 ASSERT_TRUE(report->Get(expected_a_local_relay_prflx.id()));
1894 EXPECT_EQ(expected_a_local_relay_prflx,
1895 report->Get(expected_a_local_relay_prflx.id())
1896 ->cast_to<RTCLocalIceCandidateStats>());
1897 ASSERT_TRUE(report->Get(expected_b_local.id()));
1898 EXPECT_EQ(
1899 expected_b_local,
1900 report->Get(expected_b_local.id())->cast_to<RTCLocalIceCandidateStats>());
1901 ASSERT_TRUE(report->Get(expected_b_remote.id()));
1902 EXPECT_EQ(expected_b_remote, report->Get(expected_b_remote.id())
1903 ->cast_to<RTCRemoteIceCandidateStats>());
1904 EXPECT_TRUE(report->Get("Ta0"));
1905 EXPECT_TRUE(report->Get("Tb0"));
1906 }
1907
TEST_F(RTCStatsCollectorTest,CollectRTCIceCandidatePairStats)1908 TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidatePairStats) {
1909 const char kTransportName[] = "transport";
1910
1911 std::unique_ptr<cricket::Candidate> local_candidate =
1912 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
1913 cricket::LOCAL_PORT_TYPE, 42);
1914 local_candidate->set_username("local_iceusernamefragment");
1915
1916 std::unique_ptr<cricket::Candidate> remote_candidate = CreateFakeCandidate(
1917 "42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_UNKNOWN,
1918 cricket::STUN_PORT_TYPE, 42);
1919 remote_candidate->set_related_address(rtc::SocketAddress("192.168.2.1", 43));
1920 remote_candidate->set_username("remote_iceusernamefragment");
1921
1922 cricket::ConnectionInfo connection_info;
1923 connection_info.best_connection = false;
1924 connection_info.local_candidate = *local_candidate.get();
1925 connection_info.remote_candidate = *remote_candidate.get();
1926 connection_info.writable = true;
1927 connection_info.sent_discarded_packets = 3;
1928 connection_info.sent_total_packets = 10;
1929 connection_info.packets_received = 51;
1930 connection_info.sent_discarded_bytes = 7;
1931 connection_info.sent_total_bytes = 42;
1932 connection_info.recv_total_bytes = 1234;
1933 connection_info.total_round_trip_time_ms = 0;
1934 connection_info.current_round_trip_time_ms = absl::nullopt;
1935 connection_info.recv_ping_requests = 2020;
1936 connection_info.sent_ping_requests_total = 2222;
1937 connection_info.sent_ping_requests_before_first_response = 2000;
1938 connection_info.recv_ping_responses = 4321;
1939 connection_info.sent_ping_responses = 1000;
1940 connection_info.state = cricket::IceCandidatePairState::IN_PROGRESS;
1941 connection_info.priority = 5555;
1942 connection_info.nominated = false;
1943 connection_info.last_data_received = Timestamp::Millis(2500);
1944 connection_info.last_data_sent = Timestamp::Millis(5200);
1945
1946 cricket::TransportChannelStats transport_channel_stats;
1947 transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
1948 transport_channel_stats.ice_transport_stats.connection_infos.push_back(
1949 connection_info);
1950
1951 pc_->AddVideoChannel("video", kTransportName);
1952 pc_->SetTransportStats(kTransportName, transport_channel_stats);
1953
1954 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
1955
1956 RTCIceCandidatePairStats expected_pair(
1957 "CP" + local_candidate->id() + "_" + remote_candidate->id(),
1958 report->timestamp_us());
1959 expected_pair.transport_id =
1960 "Ttransport" + rtc::ToString(cricket::ICE_CANDIDATE_COMPONENT_RTP);
1961 expected_pair.local_candidate_id = "I" + local_candidate->id();
1962 expected_pair.remote_candidate_id = "I" + remote_candidate->id();
1963 expected_pair.state = RTCStatsIceCandidatePairState::kInProgress;
1964 expected_pair.priority = 5555;
1965 expected_pair.nominated = false;
1966 expected_pair.writable = true;
1967 expected_pair.packets_sent = 7;
1968 expected_pair.packets_received = 51;
1969 expected_pair.packets_discarded_on_send = 3;
1970 expected_pair.bytes_sent = 42;
1971 expected_pair.bytes_received = 1234;
1972 expected_pair.bytes_discarded_on_send = 7;
1973 expected_pair.total_round_trip_time = 0.0;
1974 expected_pair.requests_received = 2020;
1975 expected_pair.requests_sent = 2222;
1976 expected_pair.responses_received = 4321;
1977 expected_pair.responses_sent = 1000;
1978 expected_pair.consent_requests_sent = (2222 - 2000);
1979 expected_pair.last_packet_received_timestamp = 2500;
1980 expected_pair.last_packet_sent_timestamp = 5200;
1981
1982 // `expected_pair.current_round_trip_time` should be undefined because the
1983 // current RTT is not set.
1984 // `expected_pair.available_[outgoing/incoming]_bitrate` should be undefined
1985 // because is is not the current pair.
1986
1987 ASSERT_TRUE(report->Get(expected_pair.id()));
1988 EXPECT_EQ(
1989 expected_pair,
1990 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
1991 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
1992
1993 // Set nominated and "GetStats" again.
1994 transport_channel_stats.ice_transport_stats.connection_infos[0].nominated =
1995 true;
1996 pc_->SetTransportStats(kTransportName, transport_channel_stats);
1997 report = stats_->GetFreshStatsReport();
1998 expected_pair.nominated = true;
1999 ASSERT_TRUE(report->Get(expected_pair.id()));
2000 EXPECT_EQ(
2001 expected_pair,
2002 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
2003 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
2004
2005 // Set round trip times and "GetStats" again.
2006 transport_channel_stats.ice_transport_stats.connection_infos[0]
2007 .total_round_trip_time_ms = 7331;
2008 transport_channel_stats.ice_transport_stats.connection_infos[0]
2009 .current_round_trip_time_ms = 1337;
2010 pc_->SetTransportStats(kTransportName, transport_channel_stats);
2011 report = stats_->GetFreshStatsReport();
2012 expected_pair.total_round_trip_time = 7.331;
2013 expected_pair.current_round_trip_time = 1.337;
2014 ASSERT_TRUE(report->Get(expected_pair.id()));
2015 EXPECT_EQ(
2016 expected_pair,
2017 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
2018 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
2019
2020 // Make pair the current pair, clear bandwidth and "GetStats" again.
2021 transport_channel_stats.ice_transport_stats.connection_infos[0]
2022 .best_connection = true;
2023 pc_->SetTransportStats(kTransportName, transport_channel_stats);
2024 report = stats_->GetFreshStatsReport();
2025 // |expected_pair.available_[outgoing/incoming]_bitrate| should still be
2026 // undefined because bandwidth is not set.
2027 ASSERT_TRUE(report->Get(expected_pair.id()));
2028 EXPECT_EQ(
2029 expected_pair,
2030 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
2031 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
2032
2033 // Set bandwidth and "GetStats" again.
2034 webrtc::Call::Stats call_stats;
2035 const int kSendBandwidth = 888;
2036 call_stats.send_bandwidth_bps = kSendBandwidth;
2037 const int kRecvBandwidth = 999;
2038 call_stats.recv_bandwidth_bps = kRecvBandwidth;
2039 pc_->SetCallStats(call_stats);
2040 report = stats_->GetFreshStatsReport();
2041 expected_pair.available_outgoing_bitrate = kSendBandwidth;
2042 expected_pair.available_incoming_bitrate = kRecvBandwidth;
2043 ASSERT_TRUE(report->Get(expected_pair.id()));
2044 EXPECT_EQ(
2045 expected_pair,
2046 report->Get(expected_pair.id())->cast_to<RTCIceCandidatePairStats>());
2047 EXPECT_TRUE(report->Get(*expected_pair.transport_id));
2048
2049 RTCLocalIceCandidateStats expected_local_candidate(
2050 *expected_pair.local_candidate_id, report->timestamp_us());
2051 expected_local_candidate.transport_id = *expected_pair.transport_id;
2052 expected_local_candidate.network_type = "wifi";
2053 expected_local_candidate.ip = "42.42.42.42";
2054 expected_local_candidate.address = "42.42.42.42";
2055 expected_local_candidate.port = 42;
2056 expected_local_candidate.protocol = "protocol";
2057 expected_local_candidate.candidate_type = "host";
2058 expected_local_candidate.priority = 42;
2059 expected_local_candidate.foundation = "foundationIsAString";
2060 expected_local_candidate.username_fragment = "local_iceusernamefragment";
2061 expected_local_candidate.vpn = false;
2062 expected_local_candidate.network_adapter_type = RTCNetworkAdapterType::kWifi;
2063 ASSERT_TRUE(report->Get(expected_local_candidate.id()));
2064 EXPECT_EQ(expected_local_candidate,
2065 report->Get(expected_local_candidate.id())
2066 ->cast_to<RTCLocalIceCandidateStats>());
2067
2068 RTCRemoteIceCandidateStats expected_remote_candidate(
2069 *expected_pair.remote_candidate_id, report->timestamp_us());
2070 expected_remote_candidate.transport_id = *expected_pair.transport_id;
2071 expected_remote_candidate.ip = "42.42.42.42";
2072 expected_remote_candidate.address = "42.42.42.42";
2073 expected_remote_candidate.port = 42;
2074 expected_remote_candidate.protocol = "protocol";
2075 expected_remote_candidate.candidate_type = "srflx";
2076 expected_remote_candidate.priority = 42;
2077 expected_remote_candidate.foundation = "foundationIsAString";
2078 expected_remote_candidate.username_fragment = "remote_iceusernamefragment";
2079 expected_remote_candidate.related_address = "192.168.2.1";
2080 expected_remote_candidate.related_port = 43;
2081 ASSERT_TRUE(report->Get(expected_remote_candidate.id()));
2082 EXPECT_EQ(expected_remote_candidate,
2083 report->Get(expected_remote_candidate.id())
2084 ->cast_to<RTCRemoteIceCandidateStats>());
2085 }
2086
TEST_F(RTCStatsCollectorTest,CollectRTCPeerConnectionStats)2087 TEST_F(RTCStatsCollectorTest, CollectRTCPeerConnectionStats) {
2088 {
2089 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
2090 RTCPeerConnectionStats expected("P", report->timestamp_us());
2091 expected.data_channels_opened = 0;
2092 expected.data_channels_closed = 0;
2093 ASSERT_TRUE(report->Get("P"));
2094 EXPECT_EQ(expected, report->Get("P")->cast_to<RTCPeerConnectionStats>());
2095 }
2096
2097 // TODO(bugs.webrtc.org/11547): Supply a separate network thread.
2098 FakeDataChannelController controller;
2099 rtc::scoped_refptr<SctpDataChannel> dummy_channel_a = SctpDataChannel::Create(
2100 &controller, "DummyChannelA", InternalDataChannelInit(),
2101 rtc::Thread::Current(), rtc::Thread::Current());
2102 pc_->SignalSctpDataChannelCreated()(dummy_channel_a.get());
2103 rtc::scoped_refptr<SctpDataChannel> dummy_channel_b = SctpDataChannel::Create(
2104 &controller, "DummyChannelB", InternalDataChannelInit(),
2105 rtc::Thread::Current(), rtc::Thread::Current());
2106 pc_->SignalSctpDataChannelCreated()(dummy_channel_b.get());
2107
2108 dummy_channel_a->SignalOpened(dummy_channel_a.get());
2109 // Closing a channel that is not opened should not affect the counts.
2110 dummy_channel_b->SignalClosed(dummy_channel_b.get());
2111
2112 {
2113 rtc::scoped_refptr<const RTCStatsReport> report =
2114 stats_->GetFreshStatsReport();
2115 RTCPeerConnectionStats expected("P", report->timestamp_us());
2116 expected.data_channels_opened = 1;
2117 expected.data_channels_closed = 0;
2118 ASSERT_TRUE(report->Get("P"));
2119 EXPECT_EQ(expected, report->Get("P")->cast_to<RTCPeerConnectionStats>());
2120 }
2121
2122 dummy_channel_b->SignalOpened(dummy_channel_b.get());
2123 dummy_channel_b->SignalClosed(dummy_channel_b.get());
2124
2125 {
2126 rtc::scoped_refptr<const RTCStatsReport> report =
2127 stats_->GetFreshStatsReport();
2128 RTCPeerConnectionStats expected("P", report->timestamp_us());
2129 expected.data_channels_opened = 2;
2130 expected.data_channels_closed = 1;
2131 ASSERT_TRUE(report->Get("P"));
2132 EXPECT_EQ(expected, report->Get("P")->cast_to<RTCPeerConnectionStats>());
2133 }
2134
2135 // Re-opening a data channel (or opening a new data channel that is re-using
2136 // the same address in memory) should increase the opened count.
2137 dummy_channel_b->SignalOpened(dummy_channel_b.get());
2138
2139 {
2140 rtc::scoped_refptr<const RTCStatsReport> report =
2141 stats_->GetFreshStatsReport();
2142 RTCPeerConnectionStats expected("P", report->timestamp_us());
2143 expected.data_channels_opened = 3;
2144 expected.data_channels_closed = 1;
2145 ASSERT_TRUE(report->Get("P"));
2146 EXPECT_EQ(expected, report->Get("P")->cast_to<RTCPeerConnectionStats>());
2147 }
2148
2149 dummy_channel_a->SignalClosed(dummy_channel_a.get());
2150 dummy_channel_b->SignalClosed(dummy_channel_b.get());
2151
2152 {
2153 rtc::scoped_refptr<const RTCStatsReport> report =
2154 stats_->GetFreshStatsReport();
2155 RTCPeerConnectionStats expected("P", report->timestamp_us());
2156 expected.data_channels_opened = 3;
2157 expected.data_channels_closed = 3;
2158 ASSERT_TRUE(report->Get("P"));
2159 EXPECT_EQ(expected, report->Get("P")->cast_to<RTCPeerConnectionStats>());
2160 }
2161 }
2162
TEST_F(RTCStatsCollectorTest,CollectLocalRTCMediaStreamStatsAndRTCMediaStreamTrackStats_Audio)2163 TEST_F(RTCStatsCollectorTest,
2164 CollectLocalRTCMediaStreamStatsAndRTCMediaStreamTrackStats_Audio) {
2165 rtc::scoped_refptr<MediaStream> local_stream =
2166 MediaStream::Create("LocalStreamId");
2167 pc_->mutable_local_streams()->AddStream(local_stream);
2168
2169 // Local audio track
2170 rtc::scoped_refptr<MediaStreamTrackInterface> local_audio_track =
2171 CreateFakeTrack(cricket::MEDIA_TYPE_AUDIO, "LocalAudioTrackID",
2172 MediaStreamTrackInterface::kEnded);
2173 local_stream->AddTrack(rtc::scoped_refptr<AudioTrackInterface>(
2174 static_cast<AudioTrackInterface*>(local_audio_track.get())));
2175
2176 cricket::VoiceSenderInfo voice_sender_info_ssrc1;
2177 voice_sender_info_ssrc1.local_stats.push_back(cricket::SsrcSenderInfo());
2178 voice_sender_info_ssrc1.local_stats[0].ssrc = 1;
2179 voice_sender_info_ssrc1.apm_statistics.echo_return_loss = 42.0;
2180 voice_sender_info_ssrc1.apm_statistics.echo_return_loss_enhancement = 52.0;
2181
2182 stats_->CreateMockRtpSendersReceiversAndChannels(
2183 {std::make_pair(local_audio_track.get(), voice_sender_info_ssrc1)}, {},
2184 {}, {}, {local_stream->id()}, {});
2185
2186 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
2187
2188 DEPRECATED_RTCMediaStreamStats expected_local_stream(
2189 IdForType<DEPRECATED_RTCMediaStreamStats>(report.get()),
2190 report->timestamp_us());
2191 expected_local_stream.stream_identifier = local_stream->id();
2192 expected_local_stream.track_ids = {
2193 IdForType<DEPRECATED_RTCMediaStreamTrackStats>(report.get())};
2194 ASSERT_TRUE(report->Get(expected_local_stream.id()))
2195 << "Did not find " << expected_local_stream.id() << " in "
2196 << report->ToJson();
2197 EXPECT_EQ(expected_local_stream,
2198 report->Get(expected_local_stream.id())
2199 ->cast_to<DEPRECATED_RTCMediaStreamStats>());
2200
2201 DEPRECATED_RTCMediaStreamTrackStats expected_local_audio_track_ssrc1(
2202 IdForType<DEPRECATED_RTCMediaStreamTrackStats>(report.get()),
2203 report->timestamp_us(), RTCMediaStreamTrackKind::kAudio);
2204 expected_local_audio_track_ssrc1.track_identifier = local_audio_track->id();
2205 expected_local_audio_track_ssrc1.media_source_id =
2206 "SA11"; // Attachment ID = SSRC + 10
2207 expected_local_audio_track_ssrc1.remote_source = false;
2208 expected_local_audio_track_ssrc1.ended = true;
2209 expected_local_audio_track_ssrc1.detached = false;
2210 expected_local_audio_track_ssrc1.echo_return_loss = 42.0;
2211 expected_local_audio_track_ssrc1.echo_return_loss_enhancement = 52.0;
2212 ASSERT_TRUE(report->Get(expected_local_audio_track_ssrc1.id()))
2213 << "Did not find " << expected_local_audio_track_ssrc1.id() << " in "
2214 << report->ToJson();
2215 EXPECT_EQ(expected_local_audio_track_ssrc1,
2216 report->Get(expected_local_audio_track_ssrc1.id())
2217 ->cast_to<DEPRECATED_RTCMediaStreamTrackStats>());
2218 }
2219
TEST_F(RTCStatsCollectorTest,CollectRemoteRTCMediaStreamStatsAndRTCMediaStreamTrackStats_Audio)2220 TEST_F(RTCStatsCollectorTest,
2221 CollectRemoteRTCMediaStreamStatsAndRTCMediaStreamTrackStats_Audio) {
2222 rtc::scoped_refptr<MediaStream> remote_stream =
2223 MediaStream::Create("RemoteStreamId");
2224 pc_->mutable_remote_streams()->AddStream(remote_stream);
2225
2226 // Remote audio track
2227 rtc::scoped_refptr<MediaStreamTrackInterface> remote_audio_track =
2228 CreateFakeTrack(cricket::MEDIA_TYPE_AUDIO, "RemoteAudioTrackID",
2229 MediaStreamTrackInterface::kLive);
2230 remote_stream->AddTrack(rtc::scoped_refptr<AudioTrackInterface>(
2231 static_cast<AudioTrackInterface*>(remote_audio_track.get())));
2232
2233 cricket::VoiceReceiverInfo voice_receiver_info;
2234 voice_receiver_info.local_stats.push_back(cricket::SsrcReceiverInfo());
2235 voice_receiver_info.local_stats[0].ssrc = 3;
2236 voice_receiver_info.audio_level = 16383; // [0,32767]
2237 voice_receiver_info.total_output_energy = 0.125;
2238 voice_receiver_info.total_samples_received = 4567;
2239 voice_receiver_info.total_output_duration = 0.25;
2240 voice_receiver_info.concealed_samples = 123;
2241 voice_receiver_info.concealment_events = 12;
2242 voice_receiver_info.inserted_samples_for_deceleration = 987;
2243 voice_receiver_info.removed_samples_for_acceleration = 876;
2244 voice_receiver_info.silent_concealed_samples = 765;
2245 voice_receiver_info.jitter_buffer_delay_seconds = 3.456;
2246 voice_receiver_info.jitter_buffer_emitted_count = 13;
2247
2248 stats_->CreateMockRtpSendersReceiversAndChannels(
2249 {}, {std::make_pair(remote_audio_track.get(), voice_receiver_info)}, {},
2250 {}, {}, {remote_stream});
2251
2252 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
2253
2254 DEPRECATED_RTCMediaStreamStats expected_remote_stream(
2255 IdForType<DEPRECATED_RTCMediaStreamStats>(report.get()),
2256 report->timestamp_us());
2257 expected_remote_stream.stream_identifier = remote_stream->id();
2258 expected_remote_stream.track_ids = std::vector<std::string>(
2259 {IdForType<DEPRECATED_RTCMediaStreamTrackStats>(report.get())});
2260 ASSERT_TRUE(report->Get(expected_remote_stream.id()))
2261 << "Did not find " << expected_remote_stream.id() << " in "
2262 << report->ToJson();
2263 EXPECT_EQ(expected_remote_stream,
2264 report->Get(expected_remote_stream.id())
2265 ->cast_to<DEPRECATED_RTCMediaStreamStats>());
2266
2267 DEPRECATED_RTCMediaStreamTrackStats expected_remote_audio_track(
2268 IdForType<DEPRECATED_RTCMediaStreamTrackStats>(report.get()),
2269 report->timestamp_us(), RTCMediaStreamTrackKind::kAudio);
2270 expected_remote_audio_track.track_identifier = remote_audio_track->id();
2271 // `expected_remote_audio_track.media_source_id` should be undefined
2272 // because the track is remote.
2273 expected_remote_audio_track.remote_source = true;
2274 expected_remote_audio_track.ended = false;
2275 expected_remote_audio_track.detached = false;
2276 expected_remote_audio_track.audio_level = 16383.0 / 32767.0; // [0,1]
2277 expected_remote_audio_track.total_audio_energy = 0.125;
2278 expected_remote_audio_track.total_samples_received = 4567;
2279 expected_remote_audio_track.total_samples_duration = 0.25;
2280 expected_remote_audio_track.concealed_samples = 123;
2281 expected_remote_audio_track.concealment_events = 12;
2282 expected_remote_audio_track.inserted_samples_for_deceleration = 987;
2283 expected_remote_audio_track.removed_samples_for_acceleration = 876;
2284 expected_remote_audio_track.silent_concealed_samples = 765;
2285 expected_remote_audio_track.jitter_buffer_delay = 3.456;
2286 expected_remote_audio_track.jitter_buffer_emitted_count = 13;
2287 ASSERT_TRUE(report->Get(expected_remote_audio_track.id()));
2288 EXPECT_EQ(expected_remote_audio_track,
2289 report->Get(expected_remote_audio_track.id())
2290 ->cast_to<DEPRECATED_RTCMediaStreamTrackStats>());
2291 }
2292
TEST_F(RTCStatsCollectorTest,CollectLocalRTCMediaStreamStatsAndRTCMediaStreamTrackStats_Video)2293 TEST_F(RTCStatsCollectorTest,
2294 CollectLocalRTCMediaStreamStatsAndRTCMediaStreamTrackStats_Video) {
2295 rtc::scoped_refptr<MediaStream> local_stream =
2296 MediaStream::Create("LocalStreamId");
2297 pc_->mutable_local_streams()->AddStream(local_stream);
2298
2299 // Local video track
2300 rtc::scoped_refptr<MediaStreamTrackInterface> local_video_track =
2301 CreateFakeTrack(cricket::MEDIA_TYPE_VIDEO, "LocalVideoTrackID",
2302 MediaStreamTrackInterface::kLive);
2303 local_stream->AddTrack(rtc::scoped_refptr<VideoTrackInterface>(
2304 static_cast<VideoTrackInterface*>(local_video_track.get())));
2305
2306 cricket::VideoSenderInfo video_sender_info_ssrc1;
2307 video_sender_info_ssrc1.local_stats.push_back(cricket::SsrcSenderInfo());
2308 video_sender_info_ssrc1.local_stats[0].ssrc = 1;
2309 video_sender_info_ssrc1.send_frame_width = 1234;
2310 video_sender_info_ssrc1.send_frame_height = 4321;
2311 video_sender_info_ssrc1.frames_encoded = 11;
2312 video_sender_info_ssrc1.huge_frames_sent = 1;
2313
2314 stats_->CreateMockRtpSendersReceiversAndChannels(
2315 {}, {},
2316 {std::make_pair(local_video_track.get(), video_sender_info_ssrc1)}, {},
2317 {local_stream->id()}, {});
2318
2319 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
2320
2321 auto stats_of_my_type =
2322 report->GetStatsOfType<DEPRECATED_RTCMediaStreamStats>();
2323 ASSERT_EQ(1U, stats_of_my_type.size()) << "No stream in " << report->ToJson();
2324 auto stats_of_track_type =
2325 report->GetStatsOfType<DEPRECATED_RTCMediaStreamTrackStats>();
2326 ASSERT_EQ(1U, stats_of_track_type.size())
2327 << "Wrong number of tracks in " << report->ToJson();
2328
2329 DEPRECATED_RTCMediaStreamStats expected_local_stream(
2330 stats_of_my_type[0]->id(), report->timestamp_us());
2331 expected_local_stream.stream_identifier = local_stream->id();
2332 expected_local_stream.track_ids =
2333 std::vector<std::string>({stats_of_track_type[0]->id()});
2334 ASSERT_TRUE(report->Get(expected_local_stream.id()));
2335 EXPECT_EQ(expected_local_stream,
2336 report->Get(expected_local_stream.id())
2337 ->cast_to<DEPRECATED_RTCMediaStreamStats>());
2338
2339 DEPRECATED_RTCMediaStreamTrackStats expected_local_video_track_ssrc1(
2340 stats_of_track_type[0]->id(), report->timestamp_us(),
2341 RTCMediaStreamTrackKind::kVideo);
2342 expected_local_video_track_ssrc1.track_identifier = local_video_track->id();
2343 expected_local_video_track_ssrc1.media_source_id =
2344 "SV11"; // Attachment ID = SSRC + 10
2345 expected_local_video_track_ssrc1.remote_source = false;
2346 expected_local_video_track_ssrc1.ended = false;
2347 expected_local_video_track_ssrc1.detached = false;
2348 expected_local_video_track_ssrc1.frame_width = 1234;
2349 expected_local_video_track_ssrc1.frame_height = 4321;
2350 expected_local_video_track_ssrc1.frames_sent = 11;
2351 expected_local_video_track_ssrc1.huge_frames_sent = 1;
2352 ASSERT_TRUE(report->Get(expected_local_video_track_ssrc1.id()));
2353 EXPECT_EQ(expected_local_video_track_ssrc1,
2354 report->Get(expected_local_video_track_ssrc1.id())
2355 ->cast_to<DEPRECATED_RTCMediaStreamTrackStats>());
2356 }
2357
TEST_F(RTCStatsCollectorTest,CollectRemoteRTCMediaStreamStatsAndRTCMediaStreamTrackStats_Video)2358 TEST_F(RTCStatsCollectorTest,
2359 CollectRemoteRTCMediaStreamStatsAndRTCMediaStreamTrackStats_Video) {
2360 rtc::scoped_refptr<MediaStream> remote_stream =
2361 MediaStream::Create("RemoteStreamId");
2362 pc_->mutable_remote_streams()->AddStream(remote_stream);
2363
2364 // Remote video track with values
2365 rtc::scoped_refptr<MediaStreamTrackInterface> remote_video_track_ssrc3 =
2366 CreateFakeTrack(cricket::MEDIA_TYPE_VIDEO, "RemoteVideoTrackID3",
2367 MediaStreamTrackInterface::kEnded);
2368 remote_stream->AddTrack(rtc::scoped_refptr<VideoTrackInterface>(
2369 static_cast<VideoTrackInterface*>(remote_video_track_ssrc3.get())));
2370
2371 cricket::VideoReceiverInfo video_receiver_info_ssrc3;
2372 video_receiver_info_ssrc3.local_stats.push_back(cricket::SsrcReceiverInfo());
2373 video_receiver_info_ssrc3.local_stats[0].ssrc = 3;
2374 video_receiver_info_ssrc3.frame_width = 6789;
2375 video_receiver_info_ssrc3.frame_height = 9876;
2376 video_receiver_info_ssrc3.jitter_buffer_delay_seconds = 2.5;
2377 video_receiver_info_ssrc3.jitter_buffer_emitted_count = 25;
2378 video_receiver_info_ssrc3.frames_received = 1000;
2379 video_receiver_info_ssrc3.frames_decoded = 995;
2380 video_receiver_info_ssrc3.frames_dropped = 10;
2381 video_receiver_info_ssrc3.frames_rendered = 990;
2382
2383 stats_->CreateMockRtpSendersReceiversAndChannels(
2384 {}, {}, {},
2385 {std::make_pair(remote_video_track_ssrc3.get(),
2386 video_receiver_info_ssrc3)},
2387 {}, {remote_stream});
2388
2389 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
2390
2391 auto stats_of_my_type =
2392 report->GetStatsOfType<DEPRECATED_RTCMediaStreamStats>();
2393 ASSERT_EQ(1U, stats_of_my_type.size()) << "No stream in " << report->ToJson();
2394 auto stats_of_track_type =
2395 report->GetStatsOfType<DEPRECATED_RTCMediaStreamTrackStats>();
2396 ASSERT_EQ(1U, stats_of_track_type.size())
2397 << "Wrong number of tracks in " << report->ToJson();
2398 ASSERT_TRUE(*(stats_of_track_type[0]->remote_source));
2399
2400 DEPRECATED_RTCMediaStreamStats expected_remote_stream(
2401 stats_of_my_type[0]->id(), report->timestamp_us());
2402 expected_remote_stream.stream_identifier = remote_stream->id();
2403 expected_remote_stream.track_ids =
2404 std::vector<std::string>({stats_of_track_type[0]->id()});
2405 ASSERT_TRUE(report->Get(expected_remote_stream.id()));
2406 EXPECT_EQ(expected_remote_stream,
2407 report->Get(expected_remote_stream.id())
2408 ->cast_to<DEPRECATED_RTCMediaStreamStats>());
2409
2410 DEPRECATED_RTCMediaStreamTrackStats expected_remote_video_track_ssrc3(
2411 stats_of_track_type[0]->id(), report->timestamp_us(),
2412 RTCMediaStreamTrackKind::kVideo);
2413 expected_remote_video_track_ssrc3.track_identifier =
2414 remote_video_track_ssrc3->id();
2415 // `expected_remote_video_track_ssrc3.media_source_id` should be undefined
2416 // because the track is remote.
2417 expected_remote_video_track_ssrc3.remote_source = true;
2418 expected_remote_video_track_ssrc3.ended = true;
2419 expected_remote_video_track_ssrc3.detached = false;
2420 expected_remote_video_track_ssrc3.frame_width = 6789;
2421 expected_remote_video_track_ssrc3.frame_height = 9876;
2422 expected_remote_video_track_ssrc3.jitter_buffer_delay = 2.5;
2423 expected_remote_video_track_ssrc3.jitter_buffer_emitted_count = 25;
2424 expected_remote_video_track_ssrc3.frames_received = 1000;
2425 expected_remote_video_track_ssrc3.frames_decoded = 995;
2426 expected_remote_video_track_ssrc3.frames_dropped = 10;
2427
2428 ASSERT_TRUE(report->Get(expected_remote_video_track_ssrc3.id()));
2429 EXPECT_EQ(expected_remote_video_track_ssrc3,
2430 report->Get(expected_remote_video_track_ssrc3.id())
2431 ->cast_to<DEPRECATED_RTCMediaStreamTrackStats>());
2432 }
2433
TEST_F(RTCStatsCollectorTest,CollectRTCInboundRTPStreamStats_Audio)2434 TEST_F(RTCStatsCollectorTest, CollectRTCInboundRTPStreamStats_Audio) {
2435 cricket::VoiceMediaInfo voice_media_info;
2436
2437 voice_media_info.receivers.push_back(cricket::VoiceReceiverInfo());
2438 voice_media_info.receivers[0].local_stats.push_back(
2439 cricket::SsrcReceiverInfo());
2440 voice_media_info.receivers[0].local_stats[0].ssrc = 1;
2441 voice_media_info.receivers[0].packets_lost = -1; // Signed per RFC3550
2442 voice_media_info.receivers[0].packets_discarded = 7788;
2443 voice_media_info.receivers[0].packets_rcvd = 2;
2444 voice_media_info.receivers[0].nacks_sent = 5;
2445 voice_media_info.receivers[0].fec_packets_discarded = 5566;
2446 voice_media_info.receivers[0].fec_packets_received = 6677;
2447 voice_media_info.receivers[0].payload_bytes_rcvd = 3;
2448 voice_media_info.receivers[0].header_and_padding_bytes_rcvd = 4;
2449 voice_media_info.receivers[0].codec_payload_type = 42;
2450 voice_media_info.receivers[0].jitter_ms = 4500;
2451 voice_media_info.receivers[0].jitter_buffer_delay_seconds = 1.0;
2452 voice_media_info.receivers[0].jitter_buffer_target_delay_seconds = 1.1;
2453 voice_media_info.receivers[0].jitter_buffer_minimum_delay_seconds = 0.999;
2454 voice_media_info.receivers[0].jitter_buffer_emitted_count = 2;
2455 voice_media_info.receivers[0].total_samples_received = 3;
2456 voice_media_info.receivers[0].concealed_samples = 4;
2457 voice_media_info.receivers[0].silent_concealed_samples = 5;
2458 voice_media_info.receivers[0].concealment_events = 6;
2459 voice_media_info.receivers[0].inserted_samples_for_deceleration = 7;
2460 voice_media_info.receivers[0].removed_samples_for_acceleration = 8;
2461 voice_media_info.receivers[0].audio_level = 14442; // [0,32767]
2462 voice_media_info.receivers[0].total_output_energy = 10.0;
2463 voice_media_info.receivers[0].total_output_duration = 11.0;
2464 voice_media_info.receivers[0].jitter_buffer_flushes = 7;
2465 voice_media_info.receivers[0].delayed_packet_outage_samples = 15;
2466 voice_media_info.receivers[0].relative_packet_arrival_delay_seconds = 16;
2467 voice_media_info.receivers[0].interruption_count = 7788;
2468 voice_media_info.receivers[0].total_interruption_duration_ms = 778899;
2469
2470 voice_media_info.receivers[0].last_packet_received_timestamp_ms =
2471 absl::nullopt;
2472
2473 RtpCodecParameters codec_parameters;
2474 codec_parameters.payload_type = 42;
2475 codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
2476 codec_parameters.name = "dummy";
2477 codec_parameters.clock_rate = 0;
2478 voice_media_info.receive_codecs.insert(
2479 std::make_pair(codec_parameters.payload_type, codec_parameters));
2480
2481 auto* voice_media_channel =
2482 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
2483 stats_->SetupRemoteTrackAndReceiver(
2484 cricket::MEDIA_TYPE_AUDIO, "RemoteAudioTrackID", "RemoteStreamId", 1);
2485
2486 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
2487
2488 auto stats_of_track_type =
2489 report->GetStatsOfType<DEPRECATED_RTCMediaStreamTrackStats>();
2490 ASSERT_EQ(1U, stats_of_track_type.size());
2491
2492 RTCInboundRTPStreamStats expected_audio("ITTransportName1A1",
2493 report->timestamp_us());
2494 expected_audio.ssrc = 1;
2495 expected_audio.media_type = "audio";
2496 expected_audio.kind = "audio";
2497 expected_audio.track_identifier = "RemoteAudioTrackID";
2498 expected_audio.mid = "AudioMid";
2499 expected_audio.track_id = stats_of_track_type[0]->id();
2500 expected_audio.transport_id = "TTransportName1";
2501 expected_audio.codec_id = "CITTransportName1_42";
2502 expected_audio.packets_received = 2;
2503 expected_audio.nack_count = 5;
2504 expected_audio.fec_packets_discarded = 5566;
2505 expected_audio.fec_packets_received = 6677;
2506 expected_audio.bytes_received = 3;
2507 expected_audio.header_bytes_received = 4;
2508 expected_audio.packets_lost = -1;
2509 expected_audio.packets_discarded = 7788;
2510 // `expected_audio.last_packet_received_timestamp` should be undefined.
2511 expected_audio.jitter = 4.5;
2512 expected_audio.jitter_buffer_delay = 1.0;
2513 expected_audio.jitter_buffer_target_delay = 1.1;
2514 expected_audio.jitter_buffer_minimum_delay = 0.999;
2515 expected_audio.jitter_buffer_emitted_count = 2;
2516 expected_audio.total_samples_received = 3;
2517 expected_audio.concealed_samples = 4;
2518 expected_audio.silent_concealed_samples = 5;
2519 expected_audio.concealment_events = 6;
2520 expected_audio.inserted_samples_for_deceleration = 7;
2521 expected_audio.removed_samples_for_acceleration = 8;
2522 expected_audio.audio_level = 14442.0 / 32767.0; // [0,1]
2523 expected_audio.total_audio_energy = 10.0;
2524 expected_audio.total_samples_duration = 11.0;
2525 expected_audio.jitter_buffer_flushes = 7;
2526 expected_audio.delayed_packet_outage_samples = 15;
2527 expected_audio.relative_packet_arrival_delay = 16;
2528 expected_audio.interruption_count = 7788;
2529 expected_audio.total_interruption_duration = 778.899;
2530
2531 ASSERT_TRUE(report->Get(expected_audio.id()));
2532 EXPECT_EQ(
2533 report->Get(expected_audio.id())->cast_to<RTCInboundRTPStreamStats>(),
2534 expected_audio);
2535
2536 // Set previously undefined values and "GetStats" again.
2537 voice_media_info.receivers[0].last_packet_received_timestamp_ms = 3000;
2538 expected_audio.last_packet_received_timestamp = 3000.0;
2539 voice_media_info.receivers[0].estimated_playout_ntp_timestamp_ms = 4567;
2540 expected_audio.estimated_playout_timestamp = 4567;
2541 voice_media_channel->SetStats(voice_media_info);
2542
2543 report = stats_->GetFreshStatsReport();
2544
2545 ASSERT_TRUE(report->Get(expected_audio.id()));
2546 EXPECT_EQ(
2547 report->Get(expected_audio.id())->cast_to<RTCInboundRTPStreamStats>(),
2548 expected_audio);
2549 EXPECT_TRUE(report->Get(*expected_audio.track_id));
2550 EXPECT_TRUE(report->Get(*expected_audio.transport_id));
2551 EXPECT_TRUE(report->Get(*expected_audio.codec_id));
2552 }
2553
TEST_F(RTCStatsCollectorTest,CollectRTCInboundRTPStreamStats_Video)2554 TEST_F(RTCStatsCollectorTest, CollectRTCInboundRTPStreamStats_Video) {
2555 cricket::VideoMediaInfo video_media_info;
2556
2557 video_media_info.receivers.push_back(cricket::VideoReceiverInfo());
2558 video_media_info.receivers[0].local_stats.push_back(
2559 cricket::SsrcReceiverInfo());
2560 video_media_info.receivers[0].local_stats[0].ssrc = 1;
2561 video_media_info.receivers[0].packets_rcvd = 2;
2562 video_media_info.receivers[0].packets_lost = 42;
2563 video_media_info.receivers[0].payload_bytes_rcvd = 3;
2564 video_media_info.receivers[0].header_and_padding_bytes_rcvd = 12;
2565 video_media_info.receivers[0].codec_payload_type = 42;
2566 video_media_info.receivers[0].firs_sent = 5;
2567 video_media_info.receivers[0].plis_sent = 6;
2568 video_media_info.receivers[0].nacks_sent = 7;
2569 video_media_info.receivers[0].frames_received = 8;
2570 video_media_info.receivers[0].frames_decoded = 9;
2571 video_media_info.receivers[0].key_frames_decoded = 3;
2572 video_media_info.receivers[0].frames_dropped = 13;
2573 video_media_info.receivers[0].qp_sum = absl::nullopt;
2574 video_media_info.receivers[0].total_decode_time =
2575 webrtc::TimeDelta::Seconds(9);
2576 video_media_info.receivers[0].total_processing_delay =
2577 webrtc::TimeDelta::Millis(600);
2578 video_media_info.receivers[0].total_assembly_time =
2579 webrtc::TimeDelta::Millis(500);
2580 video_media_info.receivers[0].frames_assembled_from_multiple_packets = 23;
2581 video_media_info.receivers[0].total_inter_frame_delay = 0.123;
2582 video_media_info.receivers[0].total_squared_inter_frame_delay = 0.00456;
2583 video_media_info.receivers[0].pause_count = 2;
2584 video_media_info.receivers[0].total_pauses_duration_ms = 10000;
2585 video_media_info.receivers[0].freeze_count = 3;
2586 video_media_info.receivers[0].total_freezes_duration_ms = 1000;
2587 video_media_info.receivers[0].jitter_ms = 1199;
2588 video_media_info.receivers[0].jitter_buffer_delay_seconds = 3.456;
2589 video_media_info.receivers[0].jitter_buffer_target_delay_seconds = 1.1;
2590 video_media_info.receivers[0].jitter_buffer_minimum_delay_seconds = 0.999;
2591 video_media_info.receivers[0].jitter_buffer_emitted_count = 13;
2592
2593 video_media_info.receivers[0].last_packet_received_timestamp_ms =
2594 absl::nullopt;
2595 video_media_info.receivers[0].content_type = VideoContentType::UNSPECIFIED;
2596 video_media_info.receivers[0].estimated_playout_ntp_timestamp_ms =
2597 absl::nullopt;
2598 video_media_info.receivers[0].decoder_implementation_name = "";
2599 video_media_info.receivers[0].min_playout_delay_ms = 50;
2600 video_media_info.receivers[0].power_efficient_decoder = false;
2601
2602 // Note: these two values intentionally differ,
2603 // only the decoded one should show up.
2604 video_media_info.receivers[0].framerate_rcvd = 15;
2605 video_media_info.receivers[0].framerate_decoded = 5;
2606
2607 RtpCodecParameters codec_parameters;
2608 codec_parameters.payload_type = 42;
2609 codec_parameters.kind = cricket::MEDIA_TYPE_VIDEO;
2610 codec_parameters.name = "dummy";
2611 codec_parameters.clock_rate = 0;
2612 video_media_info.receive_codecs.insert(
2613 std::make_pair(codec_parameters.payload_type, codec_parameters));
2614
2615 auto* video_media_channel =
2616 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
2617 stats_->SetupRemoteTrackAndReceiver(
2618 cricket::MEDIA_TYPE_VIDEO, "RemoteVideoTrackID", "RemoteStreamId", 1);
2619
2620 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
2621
2622 RTCInboundRTPStreamStats expected_video("ITTransportName1V1",
2623 report->timestamp_us());
2624 expected_video.ssrc = 1;
2625 expected_video.media_type = "video";
2626 expected_video.kind = "video";
2627 expected_video.track_identifier = "RemoteVideoTrackID";
2628 expected_video.mid = "VideoMid";
2629 expected_video.track_id =
2630 IdForType<DEPRECATED_RTCMediaStreamTrackStats>(report.get());
2631 expected_video.transport_id = "TTransportName1";
2632 expected_video.codec_id = "CITTransportName1_42";
2633 expected_video.fir_count = 5;
2634 expected_video.pli_count = 6;
2635 expected_video.nack_count = 7;
2636 expected_video.packets_received = 2;
2637 expected_video.bytes_received = 3;
2638 expected_video.header_bytes_received = 12;
2639 expected_video.packets_lost = 42;
2640 expected_video.frames_received = 8;
2641 expected_video.frames_decoded = 9;
2642 expected_video.key_frames_decoded = 3;
2643 expected_video.frames_dropped = 13;
2644 // `expected_video.qp_sum` should be undefined.
2645 expected_video.total_decode_time = 9.0;
2646 expected_video.total_processing_delay = 0.6;
2647 expected_video.total_assembly_time = 0.5;
2648 expected_video.frames_assembled_from_multiple_packets = 23;
2649 expected_video.total_inter_frame_delay = 0.123;
2650 expected_video.total_squared_inter_frame_delay = 0.00456;
2651 expected_video.pause_count = 2;
2652 expected_video.total_pauses_duration = 10;
2653 expected_video.freeze_count = 3;
2654 expected_video.total_freezes_duration = 1;
2655 expected_video.jitter = 1.199;
2656 expected_video.jitter_buffer_delay = 3.456;
2657 expected_video.jitter_buffer_target_delay = 1.1;
2658 expected_video.jitter_buffer_minimum_delay = 0.999;
2659 expected_video.jitter_buffer_emitted_count = 13;
2660 // `expected_video.last_packet_received_timestamp` should be undefined.
2661 // `expected_video.content_type` should be undefined.
2662 // `expected_video.decoder_implementation` should be undefined.
2663 expected_video.min_playout_delay = 0.05;
2664 expected_video.frames_per_second = 5;
2665 expected_video.power_efficient_decoder = false;
2666
2667 ASSERT_TRUE(report->Get(expected_video.id()));
2668 EXPECT_EQ(
2669 report->Get(expected_video.id())->cast_to<RTCInboundRTPStreamStats>(),
2670 expected_video);
2671
2672 // Set previously undefined values and "GetStats" again.
2673 video_media_info.receivers[0].qp_sum = 9;
2674 expected_video.qp_sum = 9;
2675 video_media_info.receivers[0].last_packet_received_timestamp_ms = 1000;
2676 expected_video.last_packet_received_timestamp = 1000.0;
2677 video_media_info.receivers[0].content_type = VideoContentType::SCREENSHARE;
2678 expected_video.content_type = "screenshare";
2679 video_media_info.receivers[0].estimated_playout_ntp_timestamp_ms = 1234;
2680 expected_video.estimated_playout_timestamp = 1234;
2681 video_media_info.receivers[0].decoder_implementation_name = "libfoodecoder";
2682 expected_video.decoder_implementation = "libfoodecoder";
2683 video_media_info.receivers[0].power_efficient_decoder = true;
2684 expected_video.power_efficient_decoder = true;
2685 video_media_channel->SetStats(video_media_info);
2686
2687 report = stats_->GetFreshStatsReport();
2688
2689 ASSERT_TRUE(report->Get(expected_video.id()));
2690 EXPECT_EQ(
2691 report->Get(expected_video.id())->cast_to<RTCInboundRTPStreamStats>(),
2692 expected_video);
2693 EXPECT_TRUE(report->Get(*expected_video.track_id));
2694 EXPECT_TRUE(report->Get(*expected_video.transport_id));
2695 EXPECT_TRUE(report->Get(*expected_video.codec_id));
2696 }
2697
TEST_F(RTCStatsCollectorTest,CollectGoogTimingFrameInfo)2698 TEST_F(RTCStatsCollectorTest, CollectGoogTimingFrameInfo) {
2699 cricket::VideoMediaInfo video_media_info;
2700
2701 video_media_info.receivers.push_back(cricket::VideoReceiverInfo());
2702 video_media_info.receivers[0].local_stats.push_back(
2703 cricket::SsrcReceiverInfo());
2704 video_media_info.receivers[0].local_stats[0].ssrc = 1;
2705 TimingFrameInfo timing_frame_info;
2706 timing_frame_info.rtp_timestamp = 1;
2707 timing_frame_info.capture_time_ms = 2;
2708 timing_frame_info.encode_start_ms = 3;
2709 timing_frame_info.encode_finish_ms = 4;
2710 timing_frame_info.packetization_finish_ms = 5;
2711 timing_frame_info.pacer_exit_ms = 6;
2712 timing_frame_info.network_timestamp_ms = 7;
2713 timing_frame_info.network2_timestamp_ms = 8;
2714 timing_frame_info.receive_start_ms = 9;
2715 timing_frame_info.receive_finish_ms = 10;
2716 timing_frame_info.decode_start_ms = 11;
2717 timing_frame_info.decode_finish_ms = 12;
2718 timing_frame_info.render_time_ms = 13;
2719 timing_frame_info.flags = 14;
2720 video_media_info.receivers[0].timing_frame_info = timing_frame_info;
2721
2722 pc_->AddVideoChannel("Mid0", "Transport0", video_media_info);
2723 stats_->SetupRemoteTrackAndReceiver(
2724 cricket::MEDIA_TYPE_VIDEO, "RemoteVideoTrackID", "RemoteStreamId", 1);
2725
2726 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
2727 auto inbound_rtps = report->GetStatsOfType<RTCInboundRTPStreamStats>();
2728 ASSERT_EQ(inbound_rtps.size(), 1u);
2729 ASSERT_TRUE(inbound_rtps[0]->goog_timing_frame_info.is_defined());
2730 EXPECT_EQ(*inbound_rtps[0]->goog_timing_frame_info,
2731 "1,2,3,4,5,6,7,8,9,10,11,12,13,1,0");
2732 }
2733
TEST_F(RTCStatsCollectorTest,CollectRTCOutboundRTPStreamStats_Audio)2734 TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRTPStreamStats_Audio) {
2735 cricket::VoiceMediaInfo voice_media_info;
2736
2737 voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
2738 voice_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
2739 voice_media_info.senders[0].local_stats[0].ssrc = 1;
2740 voice_media_info.senders[0].packets_sent = 2;
2741 voice_media_info.senders[0].total_packet_send_delay = TimeDelta::Seconds(1);
2742 voice_media_info.senders[0].retransmitted_packets_sent = 20;
2743 voice_media_info.senders[0].payload_bytes_sent = 3;
2744 voice_media_info.senders[0].header_and_padding_bytes_sent = 12;
2745 voice_media_info.senders[0].retransmitted_bytes_sent = 30;
2746 voice_media_info.senders[0].nacks_rcvd = 31;
2747 voice_media_info.senders[0].target_bitrate = 32000;
2748 voice_media_info.senders[0].codec_payload_type = 42;
2749 voice_media_info.senders[0].active = true;
2750
2751 RtpCodecParameters codec_parameters;
2752 codec_parameters.payload_type = 42;
2753 codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
2754 codec_parameters.name = "dummy";
2755 codec_parameters.clock_rate = 0;
2756 voice_media_info.send_codecs.insert(
2757 std::make_pair(codec_parameters.payload_type, codec_parameters));
2758
2759 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
2760 stats_->SetupLocalTrackAndSender(cricket::MEDIA_TYPE_AUDIO,
2761 "LocalAudioTrackID", 1, true,
2762 /*attachment_id=*/50);
2763
2764 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
2765
2766 RTCOutboundRTPStreamStats expected_audio("OTTransportName1A1",
2767 report->timestamp_us());
2768 expected_audio.media_source_id = "SA50";
2769 // `expected_audio.remote_id` should be undefined.
2770 expected_audio.mid = "AudioMid";
2771 expected_audio.ssrc = 1;
2772 expected_audio.media_type = "audio";
2773 expected_audio.kind = "audio";
2774 expected_audio.track_id =
2775 IdForType<DEPRECATED_RTCMediaStreamTrackStats>(report.get());
2776 expected_audio.transport_id = "TTransportName1";
2777 expected_audio.codec_id = "COTTransportName1_42";
2778 expected_audio.packets_sent = 2;
2779 expected_audio.total_packet_send_delay = 1;
2780 expected_audio.retransmitted_packets_sent = 20;
2781 expected_audio.bytes_sent = 3;
2782 expected_audio.header_bytes_sent = 12;
2783 expected_audio.retransmitted_bytes_sent = 30;
2784 expected_audio.nack_count = 31;
2785 expected_audio.target_bitrate = 32000;
2786 expected_audio.active = true;
2787
2788 ASSERT_TRUE(report->Get(expected_audio.id()));
2789 EXPECT_EQ(
2790 report->Get(expected_audio.id())->cast_to<RTCOutboundRTPStreamStats>(),
2791 expected_audio);
2792
2793 ASSERT_TRUE(report->Get(expected_audio.id()));
2794 EXPECT_EQ(
2795 report->Get(expected_audio.id())->cast_to<RTCOutboundRTPStreamStats>(),
2796 expected_audio);
2797 EXPECT_TRUE(report->Get(*expected_audio.track_id));
2798 EXPECT_TRUE(report->Get(*expected_audio.transport_id));
2799 EXPECT_TRUE(report->Get(*expected_audio.codec_id));
2800 }
2801
TEST_F(RTCStatsCollectorTest,CollectRTCOutboundRTPStreamStats_Video)2802 TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRTPStreamStats_Video) {
2803 cricket::VideoMediaInfo video_media_info;
2804
2805 video_media_info.senders.push_back(cricket::VideoSenderInfo());
2806 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
2807 video_media_info.senders[0].local_stats[0].ssrc = 1;
2808 video_media_info.senders[0].firs_rcvd = 2;
2809 video_media_info.senders[0].plis_rcvd = 3;
2810 video_media_info.senders[0].nacks_rcvd = 4;
2811 video_media_info.senders[0].packets_sent = 5;
2812 video_media_info.senders[0].retransmitted_packets_sent = 50;
2813 video_media_info.senders[0].payload_bytes_sent = 6;
2814 video_media_info.senders[0].header_and_padding_bytes_sent = 12;
2815 video_media_info.senders[0].retransmitted_bytes_sent = 60;
2816 video_media_info.senders[0].codec_payload_type = 42;
2817 video_media_info.senders[0].frames_encoded = 8;
2818 video_media_info.senders[0].key_frames_encoded = 3;
2819 video_media_info.senders[0].total_encode_time_ms = 9000;
2820 video_media_info.senders[0].total_encoded_bytes_target = 1234;
2821 video_media_info.senders[0].total_packet_send_delay =
2822 webrtc::TimeDelta::Seconds(10);
2823 video_media_info.senders[0].quality_limitation_reason =
2824 QualityLimitationReason::kBandwidth;
2825 video_media_info.senders[0].quality_limitation_durations_ms
2826 [webrtc::QualityLimitationReason::kBandwidth] = 300;
2827 video_media_info.senders[0].quality_limitation_resolution_changes = 56u;
2828 video_media_info.senders[0].qp_sum = absl::nullopt;
2829 video_media_info.senders[0].content_type = VideoContentType::UNSPECIFIED;
2830 video_media_info.senders[0].encoder_implementation_name = "";
2831 video_media_info.senders[0].power_efficient_encoder = false;
2832 video_media_info.senders[0].send_frame_width = 200;
2833 video_media_info.senders[0].send_frame_height = 100;
2834 video_media_info.senders[0].framerate_sent = 10;
2835 video_media_info.senders[0].frames_sent = 5;
2836 video_media_info.senders[0].huge_frames_sent = 2;
2837 video_media_info.senders[0].active = false;
2838 video_media_info.aggregated_senders.push_back(video_media_info.senders[0]);
2839 RtpCodecParameters codec_parameters;
2840 codec_parameters.payload_type = 42;
2841 codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
2842 codec_parameters.name = "dummy";
2843 codec_parameters.clock_rate = 0;
2844 video_media_info.send_codecs.insert(
2845 std::make_pair(codec_parameters.payload_type, codec_parameters));
2846
2847 auto* video_media_channel =
2848 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
2849 stats_->SetupLocalTrackAndSender(cricket::MEDIA_TYPE_VIDEO,
2850 "LocalVideoTrackID", 1, true,
2851 /*attachment_id=*/50);
2852
2853 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
2854
2855 auto stats_of_my_type = report->GetStatsOfType<RTCOutboundRTPStreamStats>();
2856 ASSERT_EQ(1U, stats_of_my_type.size());
2857 auto stats_of_track_type =
2858 report->GetStatsOfType<DEPRECATED_RTCMediaStreamTrackStats>();
2859 ASSERT_EQ(1U, stats_of_track_type.size());
2860
2861 RTCOutboundRTPStreamStats expected_video(stats_of_my_type[0]->id(),
2862 report->timestamp_us());
2863 expected_video.media_source_id = "SV50";
2864 // `expected_video.remote_id` should be undefined.
2865 expected_video.mid = "VideoMid";
2866 expected_video.ssrc = 1;
2867 expected_video.media_type = "video";
2868 expected_video.kind = "video";
2869 expected_video.track_id = stats_of_track_type[0]->id();
2870 expected_video.transport_id = "TTransportName1";
2871 expected_video.codec_id = "COTTransportName1_42";
2872 expected_video.fir_count = 2;
2873 expected_video.pli_count = 3;
2874 expected_video.nack_count = 4;
2875 expected_video.packets_sent = 5;
2876 expected_video.retransmitted_packets_sent = 50;
2877 expected_video.bytes_sent = 6;
2878 expected_video.header_bytes_sent = 12;
2879 expected_video.retransmitted_bytes_sent = 60;
2880 expected_video.frames_encoded = 8;
2881 expected_video.key_frames_encoded = 3;
2882 expected_video.total_encode_time = 9.0;
2883 expected_video.total_encoded_bytes_target = 1234;
2884 expected_video.total_packet_send_delay = 10.0;
2885 expected_video.quality_limitation_reason = "bandwidth";
2886 expected_video.quality_limitation_durations = std::map<std::string, double>{
2887 std::pair<std::string, double>{"bandwidth", 0.3},
2888 };
2889 expected_video.quality_limitation_resolution_changes = 56u;
2890 expected_video.frame_width = 200u;
2891 expected_video.frame_height = 100u;
2892 expected_video.frames_per_second = 10.0;
2893 expected_video.frames_sent = 5;
2894 expected_video.huge_frames_sent = 2;
2895 expected_video.active = false;
2896 expected_video.power_efficient_encoder = false;
2897 // `expected_video.content_type` should be undefined.
2898 // `expected_video.qp_sum` should be undefined.
2899 // `expected_video.encoder_implementation` should be undefined.
2900 ASSERT_TRUE(report->Get(expected_video.id()));
2901
2902 EXPECT_EQ(
2903 report->Get(expected_video.id())->cast_to<RTCOutboundRTPStreamStats>(),
2904 expected_video);
2905
2906 // Set previously undefined values and "GetStats" again.
2907 video_media_info.senders[0].qp_sum = 9;
2908 expected_video.qp_sum = 9;
2909 video_media_info.senders[0].content_type = VideoContentType::SCREENSHARE;
2910 expected_video.content_type = "screenshare";
2911 video_media_info.senders[0].encoder_implementation_name = "libfooencoder";
2912 video_media_info.aggregated_senders[0] = video_media_info.senders[0];
2913 expected_video.encoder_implementation = "libfooencoder";
2914 video_media_info.senders[0].power_efficient_encoder = true;
2915 expected_video.power_efficient_encoder = true;
2916 video_media_channel->SetStats(video_media_info);
2917
2918 report = stats_->GetFreshStatsReport();
2919
2920 ASSERT_TRUE(report->Get(expected_video.id()));
2921 EXPECT_EQ(
2922 report->Get(expected_video.id())->cast_to<RTCOutboundRTPStreamStats>(),
2923 expected_video);
2924 EXPECT_TRUE(report->Get(*expected_video.track_id));
2925 EXPECT_TRUE(report->Get(*expected_video.transport_id));
2926 EXPECT_TRUE(report->Get(*expected_video.codec_id));
2927 }
2928
TEST_F(RTCStatsCollectorTest,CollectRTCTransportStats)2929 TEST_F(RTCStatsCollectorTest, CollectRTCTransportStats) {
2930 const char kTransportName[] = "transport";
2931
2932 pc_->AddVoiceChannel("audio", kTransportName);
2933
2934 std::unique_ptr<cricket::Candidate> rtp_local_candidate =
2935 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
2936 cricket::LOCAL_PORT_TYPE, 42);
2937 std::unique_ptr<cricket::Candidate> rtp_remote_candidate =
2938 CreateFakeCandidate("42.42.42.42", 42, "protocol",
2939 rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
2940 42);
2941 std::unique_ptr<cricket::Candidate> rtcp_local_candidate =
2942 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
2943 cricket::LOCAL_PORT_TYPE, 42);
2944 std::unique_ptr<cricket::Candidate> rtcp_remote_candidate =
2945 CreateFakeCandidate("42.42.42.42", 42, "protocol",
2946 rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
2947 42);
2948
2949 cricket::ConnectionInfo rtp_connection_info;
2950 rtp_connection_info.best_connection = false;
2951 rtp_connection_info.local_candidate = *rtp_local_candidate.get();
2952 rtp_connection_info.remote_candidate = *rtp_remote_candidate.get();
2953 rtp_connection_info.sent_total_bytes = 42;
2954 rtp_connection_info.recv_total_bytes = 1337;
2955 rtp_connection_info.sent_total_packets = 3;
2956 rtp_connection_info.sent_discarded_packets = 2;
2957 rtp_connection_info.packets_received = 4;
2958 cricket::TransportChannelStats rtp_transport_channel_stats;
2959 rtp_transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
2960 rtp_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
2961 rtp_connection_info);
2962 rtp_transport_channel_stats.dtls_state = DtlsTransportState::kNew;
2963 rtp_transport_channel_stats.ice_transport_stats.bytes_sent = 42;
2964 rtp_transport_channel_stats.ice_transport_stats.packets_sent = 1;
2965 rtp_transport_channel_stats.ice_transport_stats.bytes_received = 1337;
2966 rtp_transport_channel_stats.ice_transport_stats.packets_received = 4;
2967 rtp_transport_channel_stats.ice_transport_stats
2968 .selected_candidate_pair_changes = 1;
2969 rtp_transport_channel_stats.ice_transport_stats.ice_local_username_fragment =
2970 "thelocalufrag";
2971 pc_->SetTransportStats(kTransportName, {rtp_transport_channel_stats});
2972
2973 // Get stats without RTCP, an active connection or certificates.
2974 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
2975
2976 RTCTransportStats expected_rtp_transport(
2977 "Ttransport" + rtc::ToString(cricket::ICE_CANDIDATE_COMPONENT_RTP),
2978 report->timestamp_us());
2979 expected_rtp_transport.bytes_sent = 42;
2980 expected_rtp_transport.packets_sent = 1;
2981 expected_rtp_transport.bytes_received = 1337;
2982 expected_rtp_transport.packets_received = 4;
2983 expected_rtp_transport.dtls_state = RTCDtlsTransportState::kNew;
2984 expected_rtp_transport.dtls_role = RTCDtlsRole::kUnknown;
2985 expected_rtp_transport.selected_candidate_pair_changes = 1;
2986 expected_rtp_transport.ice_role = RTCIceRole::kUnknown;
2987 expected_rtp_transport.ice_local_username_fragment = "thelocalufrag";
2988 expected_rtp_transport.ice_state = RTCIceTransportState::kNew;
2989
2990 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
2991 EXPECT_EQ(
2992 expected_rtp_transport,
2993 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
2994
2995 cricket::ConnectionInfo rtcp_connection_info;
2996 rtcp_connection_info.best_connection = false;
2997 rtcp_connection_info.local_candidate = *rtcp_local_candidate.get();
2998 rtcp_connection_info.remote_candidate = *rtcp_remote_candidate.get();
2999 rtcp_connection_info.sent_total_bytes = 1337;
3000 rtcp_connection_info.recv_total_bytes = 42;
3001 rtcp_connection_info.sent_total_packets = 3;
3002 rtcp_connection_info.sent_discarded_packets = 2;
3003 rtcp_connection_info.packets_received = 4;
3004 cricket::TransportChannelStats rtcp_transport_channel_stats;
3005 rtcp_transport_channel_stats.component =
3006 cricket::ICE_CANDIDATE_COMPONENT_RTCP;
3007 rtcp_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
3008 rtcp_connection_info);
3009 rtcp_transport_channel_stats.dtls_state = DtlsTransportState::kConnecting;
3010 rtcp_transport_channel_stats.ice_transport_stats.bytes_sent = 1337;
3011 rtcp_transport_channel_stats.ice_transport_stats.packets_sent = 1;
3012 rtcp_transport_channel_stats.ice_transport_stats.bytes_received = 42;
3013 rtcp_transport_channel_stats.ice_transport_stats.packets_received = 4;
3014 rtcp_transport_channel_stats.ice_transport_stats.ice_local_username_fragment =
3015 "thelocalufrag";
3016 rtcp_transport_channel_stats.ice_transport_stats.ice_state =
3017 IceTransportState::kChecking;
3018 pc_->SetTransportStats(kTransportName, {rtp_transport_channel_stats,
3019 rtcp_transport_channel_stats});
3020
3021 // Get stats with RTCP and without an active connection or certificates.
3022 report = stats_->GetFreshStatsReport();
3023
3024 RTCTransportStats expected_rtcp_transport(
3025 "Ttransport" + rtc::ToString(cricket::ICE_CANDIDATE_COMPONENT_RTCP),
3026 report->timestamp_us());
3027 expected_rtcp_transport.bytes_sent = 1337;
3028 expected_rtcp_transport.packets_sent = 1;
3029 expected_rtcp_transport.bytes_received = 42;
3030 expected_rtcp_transport.packets_received = 4;
3031 expected_rtcp_transport.dtls_state = RTCDtlsTransportState::kConnecting;
3032 expected_rtcp_transport.dtls_role = RTCDtlsRole::kUnknown;
3033 expected_rtcp_transport.selected_candidate_pair_changes = 0;
3034 expected_rtcp_transport.ice_role = RTCIceRole::kUnknown;
3035 expected_rtcp_transport.ice_local_username_fragment = "thelocalufrag";
3036 expected_rtcp_transport.ice_state = RTCIceTransportState::kChecking;
3037
3038 expected_rtp_transport.rtcp_transport_stats_id = expected_rtcp_transport.id();
3039 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
3040 EXPECT_EQ(
3041 expected_rtp_transport,
3042 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
3043 ASSERT_TRUE(report->Get(expected_rtcp_transport.id()));
3044 EXPECT_EQ(
3045 expected_rtcp_transport,
3046 report->Get(expected_rtcp_transport.id())->cast_to<RTCTransportStats>());
3047
3048 // Get stats with an active connection (selected candidate pair).
3049 rtcp_transport_channel_stats.ice_transport_stats.connection_infos[0]
3050 .best_connection = true;
3051 pc_->SetTransportStats(kTransportName, {rtp_transport_channel_stats,
3052 rtcp_transport_channel_stats});
3053
3054 report = stats_->GetFreshStatsReport();
3055
3056 expected_rtcp_transport.selected_candidate_pair_id =
3057 "CP" + rtcp_local_candidate->id() + "_" + rtcp_remote_candidate->id();
3058
3059 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
3060 EXPECT_EQ(
3061 expected_rtp_transport,
3062 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
3063 ASSERT_TRUE(report->Get(expected_rtcp_transport.id()));
3064 EXPECT_EQ(
3065 expected_rtcp_transport,
3066 report->Get(expected_rtcp_transport.id())->cast_to<RTCTransportStats>());
3067
3068 // Get stats with certificates.
3069 std::unique_ptr<CertificateInfo> local_certinfo =
3070 CreateFakeCertificateAndInfoFromDers({"(local) local", "(local) chain"});
3071 pc_->SetLocalCertificate(kTransportName, local_certinfo->certificate);
3072 std::unique_ptr<CertificateInfo> remote_certinfo =
3073 CreateFakeCertificateAndInfoFromDers(
3074 {"(remote) local", "(remote) chain"});
3075 pc_->SetRemoteCertChain(
3076 kTransportName,
3077 remote_certinfo->certificate->GetSSLCertificateChain().Clone());
3078
3079 report = stats_->GetFreshStatsReport();
3080
3081 expected_rtp_transport.local_certificate_id =
3082 "CF" + local_certinfo->fingerprints[0];
3083 expected_rtp_transport.remote_certificate_id =
3084 "CF" + remote_certinfo->fingerprints[0];
3085
3086 expected_rtcp_transport.local_certificate_id =
3087 *expected_rtp_transport.local_certificate_id;
3088 expected_rtcp_transport.remote_certificate_id =
3089 *expected_rtp_transport.remote_certificate_id;
3090
3091 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
3092 EXPECT_EQ(
3093 expected_rtp_transport,
3094 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
3095 ASSERT_TRUE(report->Get(expected_rtcp_transport.id()));
3096 EXPECT_EQ(
3097 expected_rtcp_transport,
3098 report->Get(expected_rtcp_transport.id())->cast_to<RTCTransportStats>());
3099 }
3100
TEST_F(RTCStatsCollectorTest,CollectRTCTransportStatsWithCrypto)3101 TEST_F(RTCStatsCollectorTest, CollectRTCTransportStatsWithCrypto) {
3102 const char kTransportName[] = "transport";
3103
3104 pc_->AddVoiceChannel("audio", kTransportName);
3105
3106 std::unique_ptr<cricket::Candidate> rtp_local_candidate =
3107 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
3108 cricket::LOCAL_PORT_TYPE, 42);
3109 std::unique_ptr<cricket::Candidate> rtp_remote_candidate =
3110 CreateFakeCandidate("42.42.42.42", 42, "protocol",
3111 rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
3112 42);
3113 std::unique_ptr<cricket::Candidate> rtcp_local_candidate =
3114 CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
3115 cricket::LOCAL_PORT_TYPE, 42);
3116 std::unique_ptr<cricket::Candidate> rtcp_remote_candidate =
3117 CreateFakeCandidate("42.42.42.42", 42, "protocol",
3118 rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
3119 42);
3120
3121 cricket::ConnectionInfo rtp_connection_info;
3122 rtp_connection_info.best_connection = false;
3123 rtp_connection_info.local_candidate = *rtp_local_candidate.get();
3124 rtp_connection_info.remote_candidate = *rtp_remote_candidate.get();
3125 cricket::TransportChannelStats rtp_transport_channel_stats;
3126 rtp_transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
3127 rtp_transport_channel_stats.ice_transport_stats.connection_infos.push_back(
3128 rtp_connection_info);
3129 // The state must be connected in order for crypto parameters to show up.
3130 rtp_transport_channel_stats.dtls_state = DtlsTransportState::kConnected;
3131 rtp_transport_channel_stats.ice_transport_stats
3132 .selected_candidate_pair_changes = 1;
3133 rtp_transport_channel_stats.ssl_version_bytes = 0x0203;
3134 rtp_transport_channel_stats.dtls_role = rtc::SSL_CLIENT;
3135 rtp_transport_channel_stats.ice_transport_stats.ice_role =
3136 cricket::ICEROLE_CONTROLLING;
3137 rtp_transport_channel_stats.ice_transport_stats.ice_local_username_fragment =
3138 "thelocalufrag";
3139 rtp_transport_channel_stats.ice_transport_stats.ice_state =
3140 IceTransportState::kConnected;
3141 // 0x2F is TLS_RSA_WITH_AES_128_CBC_SHA according to IANA
3142 rtp_transport_channel_stats.ssl_cipher_suite = 0x2F;
3143 rtp_transport_channel_stats.srtp_crypto_suite = rtc::kSrtpAes128CmSha1_80;
3144 pc_->SetTransportStats(kTransportName, {rtp_transport_channel_stats});
3145
3146 // Get stats
3147 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3148
3149 RTCTransportStats expected_rtp_transport(
3150 "Ttransport" + rtc::ToString(cricket::ICE_CANDIDATE_COMPONENT_RTP),
3151 report->timestamp_us());
3152 expected_rtp_transport.dtls_state = RTCDtlsTransportState::kConnected;
3153 expected_rtp_transport.selected_candidate_pair_changes = 1;
3154 expected_rtp_transport.ice_role = RTCIceRole::kUnknown;
3155 expected_rtp_transport.bytes_sent = 0;
3156 expected_rtp_transport.bytes_received = 0;
3157 expected_rtp_transport.packets_sent = 0;
3158 expected_rtp_transport.packets_received = 0;
3159 expected_rtp_transport.ice_role = RTCIceRole::kControlling;
3160 expected_rtp_transport.ice_local_username_fragment = "thelocalufrag";
3161 expected_rtp_transport.ice_state = "connected";
3162 // Crypto parameters
3163 expected_rtp_transport.tls_version = "0203";
3164 expected_rtp_transport.dtls_role = RTCDtlsRole::kClient;
3165 expected_rtp_transport.dtls_cipher = "TLS_RSA_WITH_AES_128_CBC_SHA";
3166 expected_rtp_transport.srtp_cipher = "AES_CM_128_HMAC_SHA1_80";
3167
3168 ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
3169 EXPECT_EQ(
3170 expected_rtp_transport,
3171 report->Get(expected_rtp_transport.id())->cast_to<RTCTransportStats>());
3172 }
3173
TEST_F(RTCStatsCollectorTest,CollectNoStreamRTCOutboundRTPStreamStats_Audio)3174 TEST_F(RTCStatsCollectorTest, CollectNoStreamRTCOutboundRTPStreamStats_Audio) {
3175 cricket::VoiceMediaInfo voice_media_info;
3176
3177 voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
3178 voice_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3179 voice_media_info.senders[0].local_stats[0].ssrc = 1;
3180 voice_media_info.senders[0].packets_sent = 2;
3181 voice_media_info.senders[0].total_packet_send_delay = TimeDelta::Seconds(0.5);
3182 voice_media_info.senders[0].retransmitted_packets_sent = 20;
3183 voice_media_info.senders[0].payload_bytes_sent = 3;
3184 voice_media_info.senders[0].header_and_padding_bytes_sent = 4;
3185 voice_media_info.senders[0].retransmitted_bytes_sent = 30;
3186 voice_media_info.senders[0].nacks_rcvd = 31;
3187 voice_media_info.senders[0].codec_payload_type = 42;
3188 voice_media_info.senders[0].active = true;
3189
3190 RtpCodecParameters codec_parameters;
3191 codec_parameters.payload_type = 42;
3192 codec_parameters.kind = cricket::MEDIA_TYPE_AUDIO;
3193 codec_parameters.name = "dummy";
3194 codec_parameters.clock_rate = 0;
3195 voice_media_info.send_codecs.insert(
3196 std::make_pair(codec_parameters.payload_type, codec_parameters));
3197
3198 // Emulates the case where AddTrack is used without an associated MediaStream
3199 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
3200 stats_->SetupLocalTrackAndSender(cricket::MEDIA_TYPE_AUDIO,
3201 "LocalAudioTrackID", 1, false,
3202 /*attachment_id=*/50);
3203
3204 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3205
3206 RTCOutboundRTPStreamStats expected_audio("OTTransportName1A1",
3207 report->timestamp_us());
3208 expected_audio.media_source_id = "SA50";
3209 expected_audio.mid = "AudioMid";
3210 expected_audio.ssrc = 1;
3211 expected_audio.media_type = "audio";
3212 expected_audio.kind = "audio";
3213 expected_audio.track_id =
3214 IdForType<DEPRECATED_RTCMediaStreamTrackStats>(report.get());
3215 expected_audio.transport_id = "TTransportName1";
3216 expected_audio.codec_id = "COTTransportName1_42";
3217 expected_audio.packets_sent = 2;
3218 expected_audio.total_packet_send_delay = 0.5;
3219 expected_audio.retransmitted_packets_sent = 20;
3220 expected_audio.bytes_sent = 3;
3221 expected_audio.header_bytes_sent = 4;
3222 expected_audio.retransmitted_bytes_sent = 30;
3223 expected_audio.nack_count = 31;
3224 expected_audio.active = true;
3225
3226 ASSERT_TRUE(report->Get(expected_audio.id()));
3227 EXPECT_EQ(
3228 report->Get(expected_audio.id())->cast_to<RTCOutboundRTPStreamStats>(),
3229 expected_audio);
3230 EXPECT_TRUE(report->Get(*expected_audio.track_id));
3231 EXPECT_TRUE(report->Get(*expected_audio.transport_id));
3232 EXPECT_TRUE(report->Get(*expected_audio.codec_id));
3233 }
3234
TEST_F(RTCStatsCollectorTest,RTCAudioSourceStatsCollectedForSenderWithTrack)3235 TEST_F(RTCStatsCollectorTest, RTCAudioSourceStatsCollectedForSenderWithTrack) {
3236 const uint32_t kSsrc = 4;
3237 const int kAttachmentId = 42;
3238
3239 cricket::VoiceMediaInfo voice_media_info;
3240 voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
3241 voice_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3242 voice_media_info.senders[0].local_stats[0].ssrc = kSsrc;
3243 voice_media_info.senders[0].audio_level = 32767; // [0,32767]
3244 voice_media_info.senders[0].total_input_energy = 2.0;
3245 voice_media_info.senders[0].total_input_duration = 3.0;
3246 voice_media_info.senders[0].apm_statistics.echo_return_loss = 42.0;
3247 voice_media_info.senders[0].apm_statistics.echo_return_loss_enhancement =
3248 52.0;
3249 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
3250 stats_->SetupLocalTrackAndSender(cricket::MEDIA_TYPE_AUDIO,
3251 "LocalAudioTrackID", kSsrc, false,
3252 kAttachmentId);
3253
3254 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3255
3256 RTCAudioSourceStats expected_audio("SA42", report->timestamp_us());
3257 expected_audio.track_identifier = "LocalAudioTrackID";
3258 expected_audio.kind = "audio";
3259 expected_audio.audio_level = 1.0; // [0,1]
3260 expected_audio.total_audio_energy = 2.0;
3261 expected_audio.total_samples_duration = 3.0;
3262 expected_audio.echo_return_loss = 42.0;
3263 expected_audio.echo_return_loss_enhancement = 52.0;
3264
3265 ASSERT_TRUE(report->Get(expected_audio.id()));
3266 EXPECT_EQ(report->Get(expected_audio.id())->cast_to<RTCAudioSourceStats>(),
3267 expected_audio);
3268 }
3269
TEST_F(RTCStatsCollectorTest,RTCVideoSourceStatsCollectedForSenderWithTrack)3270 TEST_F(RTCStatsCollectorTest, RTCVideoSourceStatsCollectedForSenderWithTrack) {
3271 const uint32_t kSsrc = 4;
3272 const int kAttachmentId = 42;
3273 const int kVideoSourceWidth = 12;
3274 const int kVideoSourceHeight = 34;
3275
3276 cricket::VideoMediaInfo video_media_info;
3277 video_media_info.aggregated_senders.push_back(cricket::VideoSenderInfo());
3278 video_media_info.senders.push_back(cricket::VideoSenderInfo());
3279 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3280 video_media_info.senders[0].local_stats[0].ssrc = kSsrc;
3281 video_media_info.senders[0].framerate_input = 29.0;
3282 video_media_info.aggregated_senders[0].local_stats.push_back(
3283 cricket::SsrcSenderInfo());
3284 video_media_info.aggregated_senders[0].local_stats[0].ssrc = kSsrc;
3285 video_media_info.aggregated_senders[0].framerate_input = 29.0;
3286 video_media_info.aggregated_senders[0].frames = 10001;
3287 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
3288
3289 auto video_source = FakeVideoTrackSourceForStats::Create(kVideoSourceWidth,
3290 kVideoSourceHeight);
3291 auto video_track = FakeVideoTrackForStats::Create(
3292 "LocalVideoTrackID", MediaStreamTrackInterface::kLive, video_source);
3293 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
3294 cricket::MEDIA_TYPE_VIDEO, video_track, kSsrc, kAttachmentId, {});
3295 EXPECT_CALL(*sender, Stop());
3296 EXPECT_CALL(*sender, SetMediaChannel(_));
3297 pc_->AddSender(sender);
3298
3299 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3300
3301 RTCVideoSourceStats expected_video("SV42", report->timestamp_us());
3302 expected_video.track_identifier = "LocalVideoTrackID";
3303 expected_video.kind = "video";
3304 expected_video.width = kVideoSourceWidth;
3305 expected_video.height = kVideoSourceHeight;
3306 expected_video.frames_per_second = 29.0;
3307 expected_video.frames = 10001;
3308
3309 ASSERT_TRUE(report->Get(expected_video.id()));
3310 EXPECT_EQ(report->Get(expected_video.id())->cast_to<RTCVideoSourceStats>(),
3311 expected_video);
3312 }
3313
3314 // This test exercises the current behavior and code path, but the correct
3315 // behavior is to report frame rate even if we have no SSRC.
3316 // TODO(hbos): When we know the frame rate even if we have no SSRC, update the
3317 // expectations of this test.
TEST_F(RTCStatsCollectorTest,RTCVideoSourceStatsMissingFrameRateWhenSenderHasNoSsrc)3318 TEST_F(RTCStatsCollectorTest,
3319 RTCVideoSourceStatsMissingFrameRateWhenSenderHasNoSsrc) {
3320 // TODO(https://crbug.com/webrtc/8694): When 0 is no longer a magic value for
3321 // "none", update this test.
3322 const uint32_t kNoSsrc = 0;
3323 const int kAttachmentId = 42;
3324 const int kVideoSourceWidth = 12;
3325 const int kVideoSourceHeight = 34;
3326
3327 cricket::VideoMediaInfo video_media_info;
3328 video_media_info.senders.push_back(cricket::VideoSenderInfo());
3329 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3330 video_media_info.senders[0].framerate_input = 29.0;
3331 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
3332
3333 auto video_source = FakeVideoTrackSourceForStats::Create(kVideoSourceWidth,
3334 kVideoSourceHeight);
3335 auto video_track = FakeVideoTrackForStats::Create(
3336 "LocalVideoTrackID", MediaStreamTrackInterface::kLive, video_source);
3337 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
3338 cricket::MEDIA_TYPE_VIDEO, video_track, kNoSsrc, kAttachmentId, {});
3339 EXPECT_CALL(*sender, Stop());
3340 EXPECT_CALL(*sender, SetMediaChannel(_));
3341 pc_->AddSender(sender);
3342
3343 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3344 ASSERT_TRUE(report->Get("SV42"));
3345 auto video_stats = report->Get("SV42")->cast_to<RTCVideoSourceStats>();
3346 EXPECT_FALSE(video_stats.frames_per_second.is_defined());
3347 EXPECT_FALSE(video_stats.frames.is_defined());
3348 }
3349
3350 // The track not having a source is not expected to be true in practise, but
3351 // this is true in some tests relying on fakes. This test covers that code path.
TEST_F(RTCStatsCollectorTest,RTCVideoSourceStatsMissingResolutionWhenTrackHasNoSource)3352 TEST_F(RTCStatsCollectorTest,
3353 RTCVideoSourceStatsMissingResolutionWhenTrackHasNoSource) {
3354 const uint32_t kSsrc = 4;
3355 const int kAttachmentId = 42;
3356
3357 cricket::VideoMediaInfo video_media_info;
3358 video_media_info.senders.push_back(cricket::VideoSenderInfo());
3359 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3360 video_media_info.senders[0].local_stats[0].ssrc = kSsrc;
3361 video_media_info.senders[0].framerate_input = 29.0;
3362 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
3363
3364 auto video_track = FakeVideoTrackForStats::Create(
3365 "LocalVideoTrackID", MediaStreamTrackInterface::kLive,
3366 /*source=*/nullptr);
3367 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
3368 cricket::MEDIA_TYPE_VIDEO, video_track, kSsrc, kAttachmentId, {});
3369 EXPECT_CALL(*sender, Stop());
3370 EXPECT_CALL(*sender, SetMediaChannel(_));
3371 pc_->AddSender(sender);
3372
3373 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3374 ASSERT_TRUE(report->Get("SV42"));
3375 auto video_stats = report->Get("SV42")->cast_to<RTCVideoSourceStats>();
3376 EXPECT_FALSE(video_stats.width.is_defined());
3377 EXPECT_FALSE(video_stats.height.is_defined());
3378 }
3379
TEST_F(RTCStatsCollectorTest,RTCAudioSourceStatsNotCollectedForSenderWithoutTrack)3380 TEST_F(RTCStatsCollectorTest,
3381 RTCAudioSourceStatsNotCollectedForSenderWithoutTrack) {
3382 const uint32_t kSsrc = 4;
3383 const int kAttachmentId = 42;
3384
3385 cricket::VoiceMediaInfo voice_media_info;
3386 voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
3387 voice_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3388 voice_media_info.senders[0].local_stats[0].ssrc = kSsrc;
3389 pc_->AddVoiceChannel("AudioMid", "TransportName", voice_media_info);
3390 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
3391 cricket::MEDIA_TYPE_AUDIO, /*track=*/nullptr, kSsrc, kAttachmentId, {});
3392 EXPECT_CALL(*sender, Stop());
3393 EXPECT_CALL(*sender, SetMediaChannel(_));
3394 pc_->AddSender(sender);
3395
3396 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3397 EXPECT_FALSE(report->Get("SA42"));
3398 }
3399
3400 // Parameterized tests on cricket::MediaType (audio or video).
3401 class RTCStatsCollectorTestWithParamKind
3402 : public RTCStatsCollectorTest,
3403 public ::testing::WithParamInterface<cricket::MediaType> {
3404 public:
RTCStatsCollectorTestWithParamKind()3405 RTCStatsCollectorTestWithParamKind() : media_type_(GetParam()) {
3406 RTC_DCHECK(media_type_ == cricket::MEDIA_TYPE_AUDIO ||
3407 media_type_ == cricket::MEDIA_TYPE_VIDEO);
3408 }
3409
MediaTypeCharStr() const3410 std::string MediaTypeCharStr() const {
3411 switch (media_type_) {
3412 case cricket::MEDIA_TYPE_AUDIO:
3413 return "A";
3414 case cricket::MEDIA_TYPE_VIDEO:
3415 return "V";
3416 case cricket::MEDIA_TYPE_DATA:
3417 case cricket::MEDIA_TYPE_UNSUPPORTED:
3418 RTC_DCHECK_NOTREACHED();
3419 return "?";
3420 }
3421 }
3422
MediaTypeKind() const3423 std::string MediaTypeKind() const {
3424 switch (media_type_) {
3425 case cricket::MEDIA_TYPE_AUDIO:
3426 return "audio";
3427 case cricket::MEDIA_TYPE_VIDEO:
3428 return "video";
3429 case cricket::MEDIA_TYPE_DATA:
3430 case cricket::MEDIA_TYPE_UNSUPPORTED:
3431 RTC_DCHECK_NOTREACHED();
3432 return "";
3433 }
3434 }
3435
3436 // Adds a sender and channel of the appropriate kind, creating a sender info
3437 // with the report block's `source_ssrc` and report block data.
AddSenderInfoAndMediaChannel(std::string transport_name,const std::vector<ReportBlockData> & report_block_datas,absl::optional<RtpCodecParameters> codec)3438 void AddSenderInfoAndMediaChannel(
3439 std::string transport_name,
3440 const std::vector<ReportBlockData>& report_block_datas,
3441 absl::optional<RtpCodecParameters> codec) {
3442 switch (media_type_) {
3443 case cricket::MEDIA_TYPE_AUDIO: {
3444 cricket::VoiceMediaInfo voice_media_info;
3445 for (const auto& report_block_data : report_block_datas) {
3446 cricket::VoiceSenderInfo sender;
3447 sender.local_stats.push_back(cricket::SsrcSenderInfo());
3448 sender.local_stats[0].ssrc =
3449 report_block_data.report_block().source_ssrc;
3450 if (codec.has_value()) {
3451 sender.codec_payload_type = codec->payload_type;
3452 voice_media_info.send_codecs.insert(
3453 std::make_pair(codec->payload_type, *codec));
3454 }
3455 sender.report_block_datas.push_back(report_block_data);
3456 voice_media_info.senders.push_back(sender);
3457 }
3458 pc_->AddVoiceChannel("mid", transport_name, voice_media_info);
3459 return;
3460 }
3461 case cricket::MEDIA_TYPE_VIDEO: {
3462 cricket::VideoMediaInfo video_media_info;
3463 for (const auto& report_block_data : report_block_datas) {
3464 cricket::VideoSenderInfo sender;
3465 sender.local_stats.push_back(cricket::SsrcSenderInfo());
3466 sender.local_stats[0].ssrc =
3467 report_block_data.report_block().source_ssrc;
3468 if (codec.has_value()) {
3469 sender.codec_payload_type = codec->payload_type;
3470 video_media_info.send_codecs.insert(
3471 std::make_pair(codec->payload_type, *codec));
3472 }
3473 sender.report_block_datas.push_back(report_block_data);
3474 video_media_info.aggregated_senders.push_back(sender);
3475 video_media_info.senders.push_back(sender);
3476 }
3477 pc_->AddVideoChannel("mid", transport_name, video_media_info);
3478 return;
3479 }
3480 case cricket::MEDIA_TYPE_DATA:
3481 case cricket::MEDIA_TYPE_UNSUPPORTED:
3482 RTC_DCHECK_NOTREACHED();
3483 }
3484 }
3485
3486 protected:
3487 cricket::MediaType media_type_;
3488 };
3489
3490 // Verifies RTCRemoteInboundRtpStreamStats members that don't require
3491 // RTCCodecStats (codecId, jitter) and without setting up an RTCP transport.
TEST_P(RTCStatsCollectorTestWithParamKind,RTCRemoteInboundRtpStreamStatsCollectedFromReportBlock)3492 TEST_P(RTCStatsCollectorTestWithParamKind,
3493 RTCRemoteInboundRtpStreamStatsCollectedFromReportBlock) {
3494 const int64_t kReportBlockTimestampUtcUs = 123456789;
3495 const uint8_t kFractionLost = 12;
3496 const int64_t kRoundTripTimeSample1Ms = 1234;
3497 const double kRoundTripTimeSample1Seconds = 1.234;
3498 const int64_t kRoundTripTimeSample2Ms = 13000;
3499 const double kRoundTripTimeSample2Seconds = 13;
3500
3501 // The report block's timestamp cannot be from the future, set the fake clock
3502 // to match.
3503 fake_clock_.SetTime(Timestamp::Micros(kReportBlockTimestampUtcUs));
3504 auto ssrcs = {12, 13};
3505 std::vector<ReportBlockData> report_block_datas;
3506 for (auto ssrc : ssrcs) {
3507 RTCPReportBlock report_block;
3508 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
3509 // `source_ssrc`, "SSRC of the RTP packet sender".
3510 report_block.source_ssrc = ssrc;
3511 report_block.packets_lost = 7;
3512 report_block.fraction_lost = kFractionLost;
3513 ReportBlockData report_block_data;
3514 report_block_data.SetReportBlock(report_block, kReportBlockTimestampUtcUs);
3515 report_block_data.AddRoundTripTimeSample(kRoundTripTimeSample1Ms);
3516 // Only the last sample should be exposed as the
3517 // `RTCRemoteInboundRtpStreamStats::round_trip_time`.
3518 report_block_data.AddRoundTripTimeSample(kRoundTripTimeSample2Ms);
3519 report_block_datas.push_back(report_block_data);
3520 }
3521 AddSenderInfoAndMediaChannel("TransportName", report_block_datas,
3522 absl::nullopt);
3523
3524 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3525 for (auto ssrc : ssrcs) {
3526 std::string stream_id = "" + std::to_string(ssrc);
3527 RTCRemoteInboundRtpStreamStats expected_remote_inbound_rtp(
3528 "RI" + MediaTypeCharStr() + stream_id, kReportBlockTimestampUtcUs);
3529 expected_remote_inbound_rtp.ssrc = ssrc;
3530 expected_remote_inbound_rtp.fraction_lost =
3531 static_cast<double>(kFractionLost) / (1 << 8);
3532 expected_remote_inbound_rtp.kind = MediaTypeKind();
3533 expected_remote_inbound_rtp.transport_id =
3534 "TTransportName1"; // 1 for RTP (we have no RTCP
3535 // transport)
3536 expected_remote_inbound_rtp.packets_lost = 7;
3537 expected_remote_inbound_rtp.local_id =
3538 "OTTransportName1" + MediaTypeCharStr() + stream_id;
3539 expected_remote_inbound_rtp.round_trip_time = kRoundTripTimeSample2Seconds;
3540 expected_remote_inbound_rtp.total_round_trip_time =
3541 kRoundTripTimeSample1Seconds + kRoundTripTimeSample2Seconds;
3542 expected_remote_inbound_rtp.round_trip_time_measurements = 2;
3543 // This test does not set up RTCCodecStats, so `codec_id` and `jitter` are
3544 // expected to be missing. These are tested separately.
3545
3546 ASSERT_TRUE(report->Get(expected_remote_inbound_rtp.id()));
3547 EXPECT_EQ(report->Get(expected_remote_inbound_rtp.id())
3548 ->cast_to<RTCRemoteInboundRtpStreamStats>(),
3549 expected_remote_inbound_rtp);
3550 EXPECT_TRUE(report->Get(*expected_remote_inbound_rtp.transport_id));
3551 ASSERT_TRUE(report->Get(*expected_remote_inbound_rtp.local_id));
3552 // Lookup works in both directions.
3553 EXPECT_EQ(*report->Get(*expected_remote_inbound_rtp.local_id)
3554 ->cast_to<RTCOutboundRTPStreamStats>()
3555 .remote_id,
3556 expected_remote_inbound_rtp.id());
3557 }
3558 }
3559
TEST_P(RTCStatsCollectorTestWithParamKind,RTCRemoteInboundRtpStreamStatsRttMissingBeforeMeasurement)3560 TEST_P(RTCStatsCollectorTestWithParamKind,
3561 RTCRemoteInboundRtpStreamStatsRttMissingBeforeMeasurement) {
3562 constexpr int64_t kReportBlockTimestampUtcUs = 123456789;
3563
3564 RTCPReportBlock report_block;
3565 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
3566 // `source_ssrc`, "SSRC of the RTP packet sender".
3567 report_block.source_ssrc = 12;
3568 ReportBlockData report_block_data; // AddRoundTripTimeSample() not called.
3569 report_block_data.SetReportBlock(report_block, kReportBlockTimestampUtcUs);
3570
3571 AddSenderInfoAndMediaChannel("TransportName", {report_block_data},
3572 absl::nullopt);
3573
3574 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3575
3576 std::string remote_inbound_rtp_id = "RI" + MediaTypeCharStr() + "12";
3577 ASSERT_TRUE(report->Get(remote_inbound_rtp_id));
3578 auto& remote_inbound_rtp = report->Get(remote_inbound_rtp_id)
3579 ->cast_to<RTCRemoteInboundRtpStreamStats>();
3580
3581 EXPECT_TRUE(remote_inbound_rtp.round_trip_time_measurements.is_defined());
3582 EXPECT_EQ(0, *remote_inbound_rtp.round_trip_time_measurements);
3583 EXPECT_FALSE(remote_inbound_rtp.round_trip_time.is_defined());
3584 }
3585
TEST_P(RTCStatsCollectorTestWithParamKind,RTCRemoteInboundRtpStreamStatsWithTimestampFromReportBlock)3586 TEST_P(RTCStatsCollectorTestWithParamKind,
3587 RTCRemoteInboundRtpStreamStatsWithTimestampFromReportBlock) {
3588 const int64_t kReportBlockTimestampUtcUs = 123456789;
3589 fake_clock_.SetTime(Timestamp::Micros(kReportBlockTimestampUtcUs));
3590
3591 RTCPReportBlock report_block;
3592 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
3593 // `source_ssrc`, "SSRC of the RTP packet sender".
3594 report_block.source_ssrc = 12;
3595 ReportBlockData report_block_data;
3596 report_block_data.SetReportBlock(report_block, kReportBlockTimestampUtcUs);
3597
3598 AddSenderInfoAndMediaChannel("TransportName", {report_block_data},
3599 absl::nullopt);
3600
3601 // Advance time, it should be OK to have fresher reports than report blocks.
3602 fake_clock_.AdvanceTime(TimeDelta::Micros(1234));
3603
3604 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3605
3606 std::string remote_inbound_rtp_id = "RI" + MediaTypeCharStr() + "12";
3607 ASSERT_TRUE(report->Get(remote_inbound_rtp_id));
3608 auto& remote_inbound_rtp = report->Get(remote_inbound_rtp_id)
3609 ->cast_to<RTCRemoteInboundRtpStreamStats>();
3610
3611 // Even though the report time is different, the remote-inbound-rtp timestamp
3612 // is of the time that the report block was received.
3613 EXPECT_EQ(kReportBlockTimestampUtcUs + 1234, report->timestamp_us());
3614 EXPECT_EQ(kReportBlockTimestampUtcUs, remote_inbound_rtp.timestamp_us());
3615 }
3616
TEST_P(RTCStatsCollectorTestWithParamKind,RTCRemoteInboundRtpStreamStatsWithCodecBasedMembers)3617 TEST_P(RTCStatsCollectorTestWithParamKind,
3618 RTCRemoteInboundRtpStreamStatsWithCodecBasedMembers) {
3619 const int64_t kReportBlockTimestampUtcUs = 123456789;
3620 fake_clock_.SetTime(Timestamp::Micros(kReportBlockTimestampUtcUs));
3621
3622 RTCPReportBlock report_block;
3623 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
3624 // `source_ssrc`, "SSRC of the RTP packet sender".
3625 report_block.source_ssrc = 12;
3626 report_block.jitter = 5000;
3627 ReportBlockData report_block_data;
3628 report_block_data.SetReportBlock(report_block, kReportBlockTimestampUtcUs);
3629
3630 RtpCodecParameters codec;
3631 codec.payload_type = 3;
3632 codec.kind = media_type_;
3633 codec.clock_rate = 1000;
3634
3635 AddSenderInfoAndMediaChannel("TransportName", {report_block_data}, codec);
3636
3637 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3638
3639 std::string remote_inbound_rtp_id = "RI" + MediaTypeCharStr() + "12";
3640 ASSERT_TRUE(report->Get(remote_inbound_rtp_id));
3641 auto& remote_inbound_rtp = report->Get(remote_inbound_rtp_id)
3642 ->cast_to<RTCRemoteInboundRtpStreamStats>();
3643
3644 EXPECT_TRUE(remote_inbound_rtp.codec_id.is_defined());
3645 EXPECT_TRUE(report->Get(*remote_inbound_rtp.codec_id));
3646
3647 EXPECT_TRUE(remote_inbound_rtp.jitter.is_defined());
3648 // The jitter (in seconds) is the report block's jitter divided by the codec's
3649 // clock rate.
3650 EXPECT_EQ(5.0, *remote_inbound_rtp.jitter);
3651 }
3652
TEST_P(RTCStatsCollectorTestWithParamKind,RTCRemoteInboundRtpStreamStatsWithRtcpTransport)3653 TEST_P(RTCStatsCollectorTestWithParamKind,
3654 RTCRemoteInboundRtpStreamStatsWithRtcpTransport) {
3655 const int64_t kReportBlockTimestampUtcUs = 123456789;
3656 fake_clock_.SetTime(Timestamp::Micros(kReportBlockTimestampUtcUs));
3657
3658 RTCPReportBlock report_block;
3659 // The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
3660 // `source_ssrc`, "SSRC of the RTP packet sender".
3661 report_block.source_ssrc = 12;
3662 ReportBlockData report_block_data;
3663 report_block_data.SetReportBlock(report_block, kReportBlockTimestampUtcUs);
3664
3665 cricket::TransportChannelStats rtp_transport_channel_stats;
3666 rtp_transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
3667 rtp_transport_channel_stats.dtls_state = DtlsTransportState::kNew;
3668 cricket::TransportChannelStats rtcp_transport_channel_stats;
3669 rtcp_transport_channel_stats.component =
3670 cricket::ICE_CANDIDATE_COMPONENT_RTCP;
3671 rtcp_transport_channel_stats.dtls_state = DtlsTransportState::kNew;
3672 pc_->SetTransportStats("TransportName", {rtp_transport_channel_stats,
3673 rtcp_transport_channel_stats});
3674 AddSenderInfoAndMediaChannel("TransportName", {report_block_data},
3675 absl::nullopt);
3676
3677 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3678
3679 std::string remote_inbound_rtp_id = "RI" + MediaTypeCharStr() + "12";
3680 ASSERT_TRUE(report->Get(remote_inbound_rtp_id));
3681 auto& remote_inbound_rtp = report->Get(remote_inbound_rtp_id)
3682 ->cast_to<RTCRemoteInboundRtpStreamStats>();
3683
3684 EXPECT_TRUE(remote_inbound_rtp.transport_id.is_defined());
3685 EXPECT_EQ("TTransportName2", // 2 for RTCP
3686 *remote_inbound_rtp.transport_id);
3687 EXPECT_TRUE(report->Get(*remote_inbound_rtp.transport_id));
3688 }
3689
3690 INSTANTIATE_TEST_SUITE_P(All,
3691 RTCStatsCollectorTestWithParamKind,
3692 ::testing::Values(cricket::MEDIA_TYPE_AUDIO, // "/0"
3693 cricket::MEDIA_TYPE_VIDEO)); // "/1"
3694
3695 // Checks that no remote outbound stats are collected if not available in
3696 // `VoiceMediaInfo`.
TEST_F(RTCStatsCollectorTest,RTCRemoteOutboundRtpAudioStreamStatsNotCollected)3697 TEST_F(RTCStatsCollectorTest,
3698 RTCRemoteOutboundRtpAudioStreamStatsNotCollected) {
3699 ExampleStatsGraph graph =
3700 SetupExampleStatsVoiceGraph(/*add_remote_outbound_stats=*/false);
3701 EXPECT_FALSE(graph.full_report->Get(graph.remote_outbound_rtp_id));
3702 // Also check that no other remote outbound report is created (in case the
3703 // expected ID is incorrect).
3704 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3705 ASSERT_NE(report->begin(), report->end())
3706 << "No reports have been generated.";
3707 for (const auto& stats : *report) {
3708 SCOPED_TRACE(stats.id());
3709 EXPECT_NE(stats.type(), RTCRemoteOutboundRtpStreamStats::kType);
3710 }
3711 }
3712
3713 // Checks that the remote outbound stats are collected when available in
3714 // `VoiceMediaInfo`.
TEST_F(RTCStatsCollectorTest,RTCRemoteOutboundRtpAudioStreamStatsCollected)3715 TEST_F(RTCStatsCollectorTest, RTCRemoteOutboundRtpAudioStreamStatsCollected) {
3716 ExampleStatsGraph graph =
3717 SetupExampleStatsVoiceGraph(/*add_remote_outbound_stats=*/true);
3718 ASSERT_TRUE(graph.full_report->Get(graph.remote_outbound_rtp_id));
3719 const auto& remote_outbound_rtp =
3720 graph.full_report->Get(graph.remote_outbound_rtp_id)
3721 ->cast_to<RTCRemoteOutboundRtpStreamStats>();
3722 EXPECT_EQ(remote_outbound_rtp.timestamp_us(),
3723 kRemoteOutboundStatsTimestampMs * rtc::kNumMicrosecsPerMillisec);
3724 EXPECT_FLOAT_EQ(*remote_outbound_rtp.remote_timestamp,
3725 static_cast<double>(kRemoteOutboundStatsRemoteTimestampMs));
3726 EXPECT_EQ(*remote_outbound_rtp.packets_sent, kRemoteOutboundStatsPacketsSent);
3727 EXPECT_EQ(*remote_outbound_rtp.bytes_sent, kRemoteOutboundStatsBytesSent);
3728 EXPECT_EQ(*remote_outbound_rtp.reports_sent,
3729 kRemoteOutboundStatsReportsCount);
3730 }
3731
TEST_F(RTCStatsCollectorTest,RTCVideoSourceStatsNotCollectedForSenderWithoutTrack)3732 TEST_F(RTCStatsCollectorTest,
3733 RTCVideoSourceStatsNotCollectedForSenderWithoutTrack) {
3734 const uint32_t kSsrc = 4;
3735 const int kAttachmentId = 42;
3736
3737 cricket::VideoMediaInfo video_media_info;
3738 video_media_info.senders.push_back(cricket::VideoSenderInfo());
3739 video_media_info.senders[0].local_stats.push_back(cricket::SsrcSenderInfo());
3740 video_media_info.senders[0].local_stats[0].ssrc = kSsrc;
3741 video_media_info.senders[0].framerate_input = 29.0;
3742 pc_->AddVideoChannel("VideoMid", "TransportName", video_media_info);
3743
3744 rtc::scoped_refptr<MockRtpSenderInternal> sender = CreateMockSender(
3745 cricket::MEDIA_TYPE_VIDEO, /*track=*/nullptr, kSsrc, kAttachmentId, {});
3746 EXPECT_CALL(*sender, Stop());
3747 EXPECT_CALL(*sender, SetMediaChannel(_));
3748 pc_->AddSender(sender);
3749
3750 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3751 EXPECT_FALSE(report->Get("SV42"));
3752 }
3753
3754 // Test collecting echo return loss stats from the audio processor attached to
3755 // the track, rather than the voice sender info.
TEST_F(RTCStatsCollectorTest,CollectEchoReturnLossFromTrackAudioProcessor)3756 TEST_F(RTCStatsCollectorTest, CollectEchoReturnLossFromTrackAudioProcessor) {
3757 rtc::scoped_refptr<MediaStream> local_stream =
3758 MediaStream::Create("LocalStreamId");
3759 pc_->mutable_local_streams()->AddStream(local_stream);
3760
3761 // Local audio track
3762 rtc::scoped_refptr<MediaStreamTrackInterface> local_audio_track =
3763 CreateFakeTrack(cricket::MEDIA_TYPE_AUDIO, "LocalAudioTrackID",
3764 MediaStreamTrackInterface::kEnded,
3765 /*create_fake_audio_processor=*/true);
3766 local_stream->AddTrack(rtc::scoped_refptr<AudioTrackInterface>(
3767 static_cast<AudioTrackInterface*>(local_audio_track.get())));
3768
3769 cricket::VoiceSenderInfo voice_sender_info_ssrc1;
3770 voice_sender_info_ssrc1.local_stats.push_back(cricket::SsrcSenderInfo());
3771 voice_sender_info_ssrc1.local_stats[0].ssrc = 1;
3772
3773 stats_->CreateMockRtpSendersReceiversAndChannels(
3774 {std::make_pair(local_audio_track.get(), voice_sender_info_ssrc1)}, {},
3775 {}, {}, {local_stream->id()}, {});
3776
3777 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3778
3779 DEPRECATED_RTCMediaStreamTrackStats expected_local_audio_track_ssrc1(
3780 IdForType<DEPRECATED_RTCMediaStreamTrackStats>(report.get()),
3781 report->timestamp_us(), RTCMediaStreamTrackKind::kAudio);
3782 expected_local_audio_track_ssrc1.track_identifier = local_audio_track->id();
3783 expected_local_audio_track_ssrc1.media_source_id =
3784 "SA11"; // Attachment ID = SSRC + 10
3785 expected_local_audio_track_ssrc1.remote_source = false;
3786 expected_local_audio_track_ssrc1.ended = true;
3787 expected_local_audio_track_ssrc1.detached = false;
3788 expected_local_audio_track_ssrc1.echo_return_loss = 2.0;
3789 expected_local_audio_track_ssrc1.echo_return_loss_enhancement = 3.0;
3790 ASSERT_TRUE(report->Get(expected_local_audio_track_ssrc1.id()))
3791 << "Did not find " << expected_local_audio_track_ssrc1.id() << " in "
3792 << report->ToJson();
3793 EXPECT_EQ(expected_local_audio_track_ssrc1,
3794 report->Get(expected_local_audio_track_ssrc1.id())
3795 ->cast_to<DEPRECATED_RTCMediaStreamTrackStats>());
3796
3797 RTCAudioSourceStats expected_audio("SA11", report->timestamp_us());
3798 expected_audio.track_identifier = "LocalAudioTrackID";
3799 expected_audio.kind = "audio";
3800 expected_audio.audio_level = 0;
3801 expected_audio.total_audio_energy = 0;
3802 expected_audio.total_samples_duration = 0;
3803 expected_audio.echo_return_loss = 2.0;
3804 expected_audio.echo_return_loss_enhancement = 3.0;
3805
3806 ASSERT_TRUE(report->Get(expected_audio.id()));
3807 EXPECT_EQ(report->Get(expected_audio.id())->cast_to<RTCAudioSourceStats>(),
3808 expected_audio);
3809 }
3810
TEST_F(RTCStatsCollectorTest,GetStatsWithSenderSelector)3811 TEST_F(RTCStatsCollectorTest, GetStatsWithSenderSelector) {
3812 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
3813 // Expected stats graph when filtered by sender:
3814 //
3815 // +--- track (sender)
3816 // | ^
3817 // | |
3818 // | +--------- outbound-rtp
3819 // | | | |
3820 // | | v v
3821 // | | codec (send) transport
3822 // v v
3823 // media-source
3824 rtc::scoped_refptr<const RTCStatsReport> sender_report =
3825 stats_->GetStatsReportWithSenderSelector(graph.sender);
3826 EXPECT_TRUE(sender_report);
3827 EXPECT_EQ(sender_report->timestamp_us(), graph.full_report->timestamp_us());
3828 EXPECT_EQ(sender_report->size(), 5u);
3829 EXPECT_TRUE(sender_report->Get(graph.send_codec_id));
3830 EXPECT_FALSE(sender_report->Get(graph.recv_codec_id));
3831 EXPECT_TRUE(sender_report->Get(graph.outbound_rtp_id));
3832 EXPECT_FALSE(sender_report->Get(graph.inbound_rtp_id));
3833 EXPECT_TRUE(sender_report->Get(graph.transport_id));
3834 EXPECT_TRUE(sender_report->Get(graph.sender_track_id));
3835 EXPECT_FALSE(sender_report->Get(graph.receiver_track_id));
3836 EXPECT_FALSE(sender_report->Get(graph.remote_stream_id));
3837 EXPECT_FALSE(sender_report->Get(graph.peer_connection_id));
3838 EXPECT_TRUE(sender_report->Get(graph.media_source_id));
3839 }
3840
TEST_F(RTCStatsCollectorTest,GetStatsWithReceiverSelector)3841 TEST_F(RTCStatsCollectorTest, GetStatsWithReceiverSelector) {
3842 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
3843 // Expected stats graph when filtered by receiver:
3844 //
3845 // track (receiver)
3846 // ^
3847 // |
3848 // inbound-rtp ---------------+
3849 // | |
3850 // v v
3851 // transport codec (recv)
3852 rtc::scoped_refptr<const RTCStatsReport> receiver_report =
3853 stats_->GetStatsReportWithReceiverSelector(graph.receiver);
3854 EXPECT_TRUE(receiver_report);
3855 EXPECT_EQ(receiver_report->size(), 4u);
3856 EXPECT_EQ(receiver_report->timestamp_us(), graph.full_report->timestamp_us());
3857 EXPECT_FALSE(receiver_report->Get(graph.send_codec_id));
3858 EXPECT_TRUE(receiver_report->Get(graph.recv_codec_id));
3859 EXPECT_FALSE(receiver_report->Get(graph.outbound_rtp_id));
3860 EXPECT_TRUE(receiver_report->Get(graph.inbound_rtp_id));
3861 EXPECT_TRUE(receiver_report->Get(graph.transport_id));
3862 EXPECT_FALSE(receiver_report->Get(graph.sender_track_id));
3863 EXPECT_TRUE(receiver_report->Get(graph.receiver_track_id));
3864 EXPECT_FALSE(receiver_report->Get(graph.remote_stream_id));
3865 EXPECT_FALSE(receiver_report->Get(graph.peer_connection_id));
3866 EXPECT_FALSE(receiver_report->Get(graph.media_source_id));
3867 }
3868
TEST_F(RTCStatsCollectorTest,GetStatsWithNullSenderSelector)3869 TEST_F(RTCStatsCollectorTest, GetStatsWithNullSenderSelector) {
3870 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
3871 rtc::scoped_refptr<const RTCStatsReport> empty_report =
3872 stats_->GetStatsReportWithSenderSelector(nullptr);
3873 EXPECT_TRUE(empty_report);
3874 EXPECT_EQ(empty_report->timestamp_us(), graph.full_report->timestamp_us());
3875 EXPECT_EQ(empty_report->size(), 0u);
3876 }
3877
TEST_F(RTCStatsCollectorTest,GetStatsWithNullReceiverSelector)3878 TEST_F(RTCStatsCollectorTest, GetStatsWithNullReceiverSelector) {
3879 ExampleStatsGraph graph = SetupExampleStatsGraphForSelectorTests();
3880 rtc::scoped_refptr<const RTCStatsReport> empty_report =
3881 stats_->GetStatsReportWithReceiverSelector(nullptr);
3882 EXPECT_TRUE(empty_report);
3883 EXPECT_EQ(empty_report->timestamp_us(), graph.full_report->timestamp_us());
3884 EXPECT_EQ(empty_report->size(), 0u);
3885 }
3886
3887 // When the PC has not had SetLocalDescription done, tracks all have
3888 // SSRC 0, meaning "unconnected".
3889 // In this state, we report on track stats, but not RTP stats.
TEST_F(RTCStatsCollectorTest,StatsReportedOnZeroSsrc)3890 TEST_F(RTCStatsCollectorTest, StatsReportedOnZeroSsrc) {
3891 rtc::scoped_refptr<MediaStreamTrackInterface> track =
3892 CreateFakeTrack(cricket::MEDIA_TYPE_AUDIO, "audioTrack",
3893 MediaStreamTrackInterface::kLive);
3894 rtc::scoped_refptr<MockRtpSenderInternal> sender =
3895 CreateMockSender(cricket::MEDIA_TYPE_AUDIO, track, 0, 49, {});
3896 EXPECT_CALL(*sender, Stop());
3897 pc_->AddSender(sender);
3898
3899 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3900
3901 std::vector<const DEPRECATED_RTCMediaStreamTrackStats*> track_stats =
3902 report->GetStatsOfType<DEPRECATED_RTCMediaStreamTrackStats>();
3903 EXPECT_EQ(1U, track_stats.size());
3904
3905 std::vector<const RTCRTPStreamStats*> rtp_stream_stats =
3906 report->GetStatsOfType<RTCRTPStreamStats>();
3907 EXPECT_EQ(0U, rtp_stream_stats.size());
3908 }
3909
TEST_F(RTCStatsCollectorTest,DoNotCrashOnSsrcChange)3910 TEST_F(RTCStatsCollectorTest, DoNotCrashOnSsrcChange) {
3911 rtc::scoped_refptr<MediaStreamTrackInterface> track =
3912 CreateFakeTrack(cricket::MEDIA_TYPE_AUDIO, "audioTrack",
3913 MediaStreamTrackInterface::kLive);
3914 rtc::scoped_refptr<MockRtpSenderInternal> sender =
3915 CreateMockSender(cricket::MEDIA_TYPE_AUDIO, track, 4711, 49, {});
3916 EXPECT_CALL(*sender, Stop());
3917 pc_->AddSender(sender);
3918
3919 // We do not generate any matching voice_sender_info stats.
3920 rtc::scoped_refptr<const RTCStatsReport> report = stats_->GetStatsReport();
3921
3922 std::vector<const DEPRECATED_RTCMediaStreamTrackStats*> track_stats =
3923 report->GetStatsOfType<DEPRECATED_RTCMediaStreamTrackStats>();
3924 EXPECT_EQ(1U, track_stats.size());
3925 }
3926
3927 // Used for test below, to test calling GetStatsReport during a callback.
3928 class RecursiveCallback : public RTCStatsCollectorCallback {
3929 public:
RecursiveCallback(RTCStatsCollectorWrapper * stats)3930 explicit RecursiveCallback(RTCStatsCollectorWrapper* stats) : stats_(stats) {}
3931
OnStatsDelivered(const rtc::scoped_refptr<const RTCStatsReport> & report)3932 void OnStatsDelivered(
3933 const rtc::scoped_refptr<const RTCStatsReport>& report) override {
3934 stats_->GetStatsReport();
3935 called_ = true;
3936 }
3937
called() const3938 bool called() const { return called_; }
3939
3940 private:
3941 RTCStatsCollectorWrapper* stats_;
3942 bool called_ = false;
3943 };
3944
3945 // Test that nothing bad happens if a callback causes GetStatsReport to be
3946 // called again recursively. Regression test for crbug.com/webrtc/8973.
TEST_F(RTCStatsCollectorTest,DoNotCrashWhenGetStatsCalledDuringCallback)3947 TEST_F(RTCStatsCollectorTest, DoNotCrashWhenGetStatsCalledDuringCallback) {
3948 auto callback1 = rtc::make_ref_counted<RecursiveCallback>(stats_.get());
3949 auto callback2 = rtc::make_ref_counted<RecursiveCallback>(stats_.get());
3950 stats_->stats_collector()->GetStatsReport(callback1);
3951 stats_->stats_collector()->GetStatsReport(callback2);
3952 EXPECT_TRUE_WAIT(callback1->called(), kGetStatsReportTimeoutMs);
3953 EXPECT_TRUE_WAIT(callback2->called(), kGetStatsReportTimeoutMs);
3954 }
3955
3956 class RTCTestStats : public RTCStats {
3957 public:
3958 WEBRTC_RTCSTATS_DECL();
3959
RTCTestStats(const std::string & id,int64_t timestamp_us)3960 RTCTestStats(const std::string& id, int64_t timestamp_us)
3961 : RTCStats(id, timestamp_us), dummy_stat("dummyStat") {}
3962
3963 RTCStatsMember<int32_t> dummy_stat;
3964 };
3965
3966 WEBRTC_RTCSTATS_IMPL(RTCTestStats, RTCStats, "test-stats", &dummy_stat)
3967
3968 // Overrides the stats collection to verify thread usage and that the resulting
3969 // partial reports are merged.
3970 class FakeRTCStatsCollector : public RTCStatsCollector,
3971 public RTCStatsCollectorCallback {
3972 public:
Create(PeerConnectionInternal * pc,int64_t cache_lifetime_us)3973 static rtc::scoped_refptr<FakeRTCStatsCollector> Create(
3974 PeerConnectionInternal* pc,
3975 int64_t cache_lifetime_us) {
3976 return rtc::scoped_refptr<FakeRTCStatsCollector>(
3977 new rtc::RefCountedObject<FakeRTCStatsCollector>(pc,
3978 cache_lifetime_us));
3979 }
3980
3981 // Since FakeRTCStatsCollector inherits twice from RefCountInterface, once via
3982 // RTCStatsCollector and once via RTCStatsCollectorCallback, scoped_refptr
3983 // will get confused about which AddRef()/Release() methods to call.
3984 // So to remove all doubt, we declare them here again in the class that we
3985 // give to scoped_refptr.
3986 // Satisfying the implementation of these methods and associating them with a
3987 // reference counter, will be done by RefCountedObject.
3988 virtual void AddRef() const = 0;
3989 virtual rtc::RefCountReleaseStatus Release() const = 0;
3990
3991 // RTCStatsCollectorCallback implementation.
OnStatsDelivered(const rtc::scoped_refptr<const RTCStatsReport> & report)3992 void OnStatsDelivered(
3993 const rtc::scoped_refptr<const RTCStatsReport>& report) override {
3994 EXPECT_TRUE(signaling_thread_->IsCurrent());
3995 MutexLock lock(&lock_);
3996 delivered_report_ = report;
3997 }
3998
VerifyThreadUsageAndResultsMerging()3999 void VerifyThreadUsageAndResultsMerging() {
4000 GetStatsReport(rtc::scoped_refptr<RTCStatsCollectorCallback>(this));
4001 EXPECT_TRUE_WAIT(HasVerifiedResults(), kGetStatsReportTimeoutMs);
4002 }
4003
HasVerifiedResults()4004 bool HasVerifiedResults() {
4005 EXPECT_TRUE(signaling_thread_->IsCurrent());
4006 MutexLock lock(&lock_);
4007 if (!delivered_report_)
4008 return false;
4009 EXPECT_EQ(produced_on_signaling_thread_, 1);
4010 EXPECT_EQ(produced_on_network_thread_, 1);
4011
4012 EXPECT_TRUE(delivered_report_->Get("SignalingThreadStats"));
4013 EXPECT_TRUE(delivered_report_->Get("NetworkThreadStats"));
4014
4015 produced_on_signaling_thread_ = 0;
4016 produced_on_network_thread_ = 0;
4017 delivered_report_ = nullptr;
4018 return true;
4019 }
4020
4021 protected:
FakeRTCStatsCollector(PeerConnectionInternal * pc,int64_t cache_lifetime)4022 FakeRTCStatsCollector(PeerConnectionInternal* pc, int64_t cache_lifetime)
4023 : RTCStatsCollector(pc, cache_lifetime),
4024 signaling_thread_(pc->signaling_thread()),
4025 worker_thread_(pc->worker_thread()),
4026 network_thread_(pc->network_thread()) {}
4027
ProducePartialResultsOnSignalingThreadImpl(int64_t timestamp_us,RTCStatsReport * partial_report)4028 void ProducePartialResultsOnSignalingThreadImpl(
4029 int64_t timestamp_us,
4030 RTCStatsReport* partial_report) override {
4031 EXPECT_TRUE(signaling_thread_->IsCurrent());
4032 {
4033 MutexLock lock(&lock_);
4034 EXPECT_FALSE(delivered_report_);
4035 ++produced_on_signaling_thread_;
4036 }
4037
4038 partial_report->AddStats(std::unique_ptr<const RTCStats>(
4039 new RTCTestStats("SignalingThreadStats", timestamp_us)));
4040 }
ProducePartialResultsOnNetworkThreadImpl(int64_t timestamp_us,const std::map<std::string,cricket::TransportStats> & transport_stats_by_name,const std::map<std::string,CertificateStatsPair> & transport_cert_stats,RTCStatsReport * partial_report)4041 void ProducePartialResultsOnNetworkThreadImpl(
4042 int64_t timestamp_us,
4043 const std::map<std::string, cricket::TransportStats>&
4044 transport_stats_by_name,
4045 const std::map<std::string, CertificateStatsPair>& transport_cert_stats,
4046 RTCStatsReport* partial_report) override {
4047 EXPECT_TRUE(network_thread_->IsCurrent());
4048 {
4049 MutexLock lock(&lock_);
4050 EXPECT_FALSE(delivered_report_);
4051 ++produced_on_network_thread_;
4052 }
4053
4054 partial_report->AddStats(std::unique_ptr<const RTCStats>(
4055 new RTCTestStats("NetworkThreadStats", timestamp_us)));
4056 }
4057
4058 private:
4059 rtc::Thread* const signaling_thread_;
4060 rtc::Thread* const worker_thread_;
4061 rtc::Thread* const network_thread_;
4062
4063 Mutex lock_;
4064 rtc::scoped_refptr<const RTCStatsReport> delivered_report_;
4065 int produced_on_signaling_thread_ = 0;
4066 int produced_on_network_thread_ = 0;
4067 };
4068
TEST(RTCStatsCollectorTestWithFakeCollector,ThreadUsageAndResultsMerging)4069 TEST(RTCStatsCollectorTestWithFakeCollector, ThreadUsageAndResultsMerging) {
4070 rtc::AutoThread main_thread_;
4071 auto pc = rtc::make_ref_counted<FakePeerConnectionForStats>();
4072 rtc::scoped_refptr<FakeRTCStatsCollector> stats_collector(
4073 FakeRTCStatsCollector::Create(pc.get(),
4074 50 * rtc::kNumMicrosecsPerMillisec));
4075 stats_collector->VerifyThreadUsageAndResultsMerging();
4076 }
4077
4078 } // namespace
4079
4080 } // namespace webrtc
4081