OLD | NEW |
| (Empty) |
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 <set> | |
12 #include <vector> | |
13 | |
14 #include "webrtc/api/datachannelinterface.h" | |
15 #include "webrtc/api/peerconnectioninterface.h" | |
16 #include "webrtc/api/stats/rtcstats_objects.h" | |
17 #include "webrtc/api/stats/rtcstatsreport.h" | |
18 #include "webrtc/api/test/peerconnectiontestwrapper.h" | |
19 #include "webrtc/api/test/rtcstatsobtainer.h" | |
20 #include "webrtc/base/checks.h" | |
21 #include "webrtc/base/gunit.h" | |
22 #include "webrtc/base/physicalsocketserver.h" | |
23 #include "webrtc/base/refcountedobject.h" | |
24 #include "webrtc/base/scoped_ref_ptr.h" | |
25 #include "webrtc/base/virtualsocketserver.h" | |
26 | |
27 namespace webrtc { | |
28 | |
29 namespace { | |
30 | |
31 const int64_t kGetStatsTimeoutMs = 10000; | |
32 | |
33 class RTCStatsIntegrationTest : public testing::Test { | |
34 public: | |
35 RTCStatsIntegrationTest() | |
36 : physical_socket_server_(), | |
37 virtual_socket_server_(&physical_socket_server_), | |
38 network_thread_(&virtual_socket_server_), | |
39 worker_thread_() { | |
40 RTC_CHECK(network_thread_.Start()); | |
41 RTC_CHECK(worker_thread_.Start()); | |
42 | |
43 caller_ = new rtc::RefCountedObject<PeerConnectionTestWrapper>( | |
44 "caller", &network_thread_, &worker_thread_); | |
45 callee_ = new rtc::RefCountedObject<PeerConnectionTestWrapper>( | |
46 "callee", &network_thread_, &worker_thread_); | |
47 } | |
48 | |
49 void StartCall() { | |
50 // Create PeerConnections and "connect" sigslots | |
51 PeerConnectionInterface::RTCConfiguration config; | |
52 PeerConnectionInterface::IceServer ice_server; | |
53 ice_server.uri = "stun:1.1.1.1:3478"; | |
54 config.servers.push_back(ice_server); | |
55 EXPECT_TRUE(caller_->CreatePc(nullptr, config)); | |
56 EXPECT_TRUE(callee_->CreatePc(nullptr, config)); | |
57 PeerConnectionTestWrapper::Connect(caller_.get(), callee_.get()); | |
58 | |
59 // Get user media for audio and video | |
60 caller_->GetAndAddUserMedia(true, FakeConstraints(), | |
61 true, FakeConstraints()); | |
62 callee_->GetAndAddUserMedia(true, FakeConstraints(), | |
63 true, FakeConstraints()); | |
64 | |
65 // Create data channels | |
66 DataChannelInit init; | |
67 caller_->CreateDataChannel("data", init); | |
68 callee_->CreateDataChannel("data", init); | |
69 | |
70 // Negotiate and wait for call to establish | |
71 caller_->CreateOffer(nullptr); | |
72 caller_->WaitForCallEstablished(); | |
73 callee_->WaitForCallEstablished(); | |
74 } | |
75 | |
76 rtc::scoped_refptr<const RTCStatsReport> GetStatsFromCaller() { | |
77 return GetStats(caller_->pc()); | |
78 } | |
79 | |
80 rtc::scoped_refptr<const RTCStatsReport> GetStatsFromCallee() { | |
81 return GetStats(callee_->pc()); | |
82 } | |
83 | |
84 protected: | |
85 static rtc::scoped_refptr<const RTCStatsReport> GetStats( | |
86 PeerConnectionInterface* pc) { | |
87 rtc::scoped_refptr<RTCStatsObtainer> stats_obtainer = | |
88 RTCStatsObtainer::Create(); | |
89 pc->GetStats(stats_obtainer); | |
90 EXPECT_TRUE_WAIT(stats_obtainer->report(), kGetStatsTimeoutMs); | |
91 return stats_obtainer->report(); | |
92 } | |
93 | |
94 // These objects use each other and must be constructed/destroyed in this | |
95 // order. Relationship: | |
96 // |physical_socket_server_| <- |virtual_socket_server_| <- |network_thread_| | |
97 rtc::PhysicalSocketServer physical_socket_server_; | |
98 rtc::VirtualSocketServer virtual_socket_server_; | |
99 rtc::Thread network_thread_; | |
100 rtc::Thread worker_thread_; | |
101 rtc::scoped_refptr<PeerConnectionTestWrapper> caller_; | |
102 rtc::scoped_refptr<PeerConnectionTestWrapper> callee_; | |
103 }; | |
104 | |
105 class RTCStatsVerifier { | |
106 public: | |
107 RTCStatsVerifier(const RTCStatsReport* report, const RTCStats* stats) | |
108 : report_(report), stats_(stats), all_tests_successful_(true) { | |
109 RTC_CHECK(report_); | |
110 RTC_CHECK(stats_); | |
111 for (const RTCStatsMemberInterface* member : stats_->Members()) { | |
112 untested_members_.insert(member); | |
113 } | |
114 } | |
115 | |
116 void MarkMemberTested( | |
117 const RTCStatsMemberInterface& member, bool test_successful) { | |
118 untested_members_.erase(&member); | |
119 all_tests_successful_ &= test_successful; | |
120 } | |
121 | |
122 void TestMemberIsDefined(const RTCStatsMemberInterface& member) { | |
123 EXPECT_TRUE(member.is_defined()) << | |
124 stats_->type() << "." << member.name() << "[" << stats_->id() << | |
125 "] was undefined."; | |
126 MarkMemberTested(member, member.is_defined()); | |
127 } | |
128 | |
129 void TestMemberIsUndefined(const RTCStatsMemberInterface& member) { | |
130 EXPECT_FALSE(member.is_defined()) << | |
131 stats_->type() << "." << member.name() << "[" << stats_->id() << | |
132 "] was defined (" << member.ValueToString() << ")."; | |
133 MarkMemberTested(member, !member.is_defined()); | |
134 } | |
135 | |
136 template<typename T> | |
137 void TestMemberIsPositive(const RTCStatsMemberInterface& member) { | |
138 EXPECT_TRUE(member.is_defined()) << | |
139 stats_->type() << "." << member.name() << "[" << stats_->id() << | |
140 "] was undefined."; | |
141 if (!member.is_defined()) { | |
142 MarkMemberTested(member, false); | |
143 return; | |
144 } | |
145 bool is_positive = *member.cast_to<RTCStatsMember<T>>() > T(0); | |
146 EXPECT_TRUE(is_positive) << | |
147 stats_->type() << "." << member.name() << "[" << stats_->id() << | |
148 "] was not positive (" << member.ValueToString() << ")."; | |
149 MarkMemberTested(member, is_positive); | |
150 } | |
151 | |
152 template<typename T> | |
153 void TestMemberIsNonNegative(const RTCStatsMemberInterface& member) { | |
154 EXPECT_TRUE(member.is_defined()) << | |
155 stats_->type() << "." << member.name() << "[" << stats_->id() << | |
156 "] was undefined."; | |
157 if (!member.is_defined()) { | |
158 MarkMemberTested(member, false); | |
159 return; | |
160 } | |
161 bool is_non_negative = *member.cast_to<RTCStatsMember<T>>() >= T(0); | |
162 EXPECT_TRUE(is_non_negative) << | |
163 stats_->type() << "." << member.name() << "[" << stats_->id() << | |
164 "] was not non-negative (" << member.ValueToString() << ")."; | |
165 MarkMemberTested(member, is_non_negative); | |
166 } | |
167 | |
168 void TestMemberIsIDReference( | |
169 const RTCStatsMemberInterface& member, | |
170 const char* expected_type) { | |
171 TestMemberIsIDReference(member, expected_type, false); | |
172 } | |
173 | |
174 void TestMemberIsOptionalIDReference( | |
175 const RTCStatsMemberInterface& member, | |
176 const char* expected_type) { | |
177 TestMemberIsIDReference(member, expected_type, true); | |
178 } | |
179 | |
180 bool ExpectAllMembersSuccessfullyTested() { | |
181 if (untested_members_.empty()) | |
182 return all_tests_successful_; | |
183 for (const RTCStatsMemberInterface* member : untested_members_) { | |
184 EXPECT_TRUE(false) << | |
185 stats_->type() << "." << member->name() << "[" << stats_->id() << | |
186 "] was not tested."; | |
187 } | |
188 return false; | |
189 } | |
190 | |
191 private: | |
192 void TestMemberIsIDReference( | |
193 const RTCStatsMemberInterface& member, | |
194 const char* expected_type, | |
195 bool optional) { | |
196 if (optional && !member.is_defined()) { | |
197 MarkMemberTested(member, true); | |
198 return; | |
199 } | |
200 bool valid_reference = false; | |
201 if (member.is_defined()) { | |
202 if (member.type() == RTCStatsMemberInterface::kString) { | |
203 // A single ID. | |
204 const RTCStatsMember<std::string>& id = | |
205 member.cast_to<RTCStatsMember<std::string>>(); | |
206 const RTCStats* referenced_stats = report_->Get(*id); | |
207 valid_reference = | |
208 referenced_stats && referenced_stats->type() == expected_type; | |
209 } else if (member.type() == RTCStatsMemberInterface::kSequenceString) { | |
210 // A vector of IDs. | |
211 valid_reference = true; | |
212 const RTCStatsMember<std::vector<std::string>>& ids = | |
213 member.cast_to<RTCStatsMember<std::vector<std::string>>>(); | |
214 for (const std::string id : *ids) { | |
215 const RTCStats* referenced_stats = report_->Get(id); | |
216 if (!referenced_stats || referenced_stats->type() != expected_type) { | |
217 valid_reference = false; | |
218 break; | |
219 } | |
220 } | |
221 } | |
222 } | |
223 EXPECT_TRUE(valid_reference) << | |
224 stats_->type() << "." << member.name() << " is not a reference to an " << | |
225 "existing dictionary of type " << expected_type << " (" << | |
226 member.ValueToString() << ")."; | |
227 MarkMemberTested(member, valid_reference); | |
228 } | |
229 | |
230 rtc::scoped_refptr<const RTCStatsReport> report_; | |
231 const RTCStats* stats_; | |
232 std::set<const RTCStatsMemberInterface*> untested_members_; | |
233 bool all_tests_successful_; | |
234 }; | |
235 | |
236 class RTCStatsReportVerifier { | |
237 public: | |
238 static std::set<const char*> StatsTypes() { | |
239 std::set<const char*> stats_types; | |
240 stats_types.insert(RTCCertificateStats::kType); | |
241 stats_types.insert(RTCCodecStats::kType); | |
242 stats_types.insert(RTCDataChannelStats::kType); | |
243 stats_types.insert(RTCIceCandidatePairStats::kType); | |
244 stats_types.insert(RTCLocalIceCandidateStats::kType); | |
245 stats_types.insert(RTCRemoteIceCandidateStats::kType); | |
246 stats_types.insert(RTCMediaStreamStats::kType); | |
247 stats_types.insert(RTCMediaStreamTrackStats::kType); | |
248 stats_types.insert(RTCPeerConnectionStats::kType); | |
249 stats_types.insert(RTCInboundRTPStreamStats::kType); | |
250 stats_types.insert(RTCOutboundRTPStreamStats::kType); | |
251 stats_types.insert(RTCTransportStats::kType); | |
252 return stats_types; | |
253 } | |
254 | |
255 explicit RTCStatsReportVerifier(const RTCStatsReport* report) | |
256 : report_(report) { | |
257 } | |
258 | |
259 void VerifyReport() { | |
260 std::set<const char*> missing_stats = StatsTypes(); | |
261 bool verify_successful = true; | |
262 for (const RTCStats& stats : *report_) { | |
263 missing_stats.erase(stats.type()); | |
264 if (stats.type() == RTCCertificateStats::kType) { | |
265 verify_successful &= VerifyRTCCertificateStats( | |
266 stats.cast_to<RTCCertificateStats>()); | |
267 } else if (stats.type() == RTCCodecStats::kType) { | |
268 verify_successful &= VerifyRTCCodecStats( | |
269 stats.cast_to<RTCCodecStats>()); | |
270 } else if (stats.type() == RTCDataChannelStats::kType) { | |
271 verify_successful &= VerifyRTCDataChannelStats( | |
272 stats.cast_to<RTCDataChannelStats>()); | |
273 } else if (stats.type() == RTCIceCandidatePairStats::kType) { | |
274 verify_successful &= VerifyRTCIceCandidatePairStats( | |
275 stats.cast_to<RTCIceCandidatePairStats>()); | |
276 } else if (stats.type() == RTCLocalIceCandidateStats::kType) { | |
277 verify_successful &= VerifyRTCLocalIceCandidateStats( | |
278 stats.cast_to<RTCLocalIceCandidateStats>()); | |
279 } else if (stats.type() == RTCRemoteIceCandidateStats::kType) { | |
280 verify_successful &= VerifyRTCRemoteIceCandidateStats( | |
281 stats.cast_to<RTCRemoteIceCandidateStats>()); | |
282 } else if (stats.type() == RTCMediaStreamStats::kType) { | |
283 verify_successful &= VerifyRTCMediaStreamStats( | |
284 stats.cast_to<RTCMediaStreamStats>()); | |
285 } else if (stats.type() == RTCMediaStreamTrackStats::kType) { | |
286 verify_successful &= VerifyRTCMediaStreamTrackStats( | |
287 stats.cast_to<RTCMediaStreamTrackStats>()); | |
288 } else if (stats.type() == RTCPeerConnectionStats::kType) { | |
289 verify_successful &= VerifyRTCPeerConnectionStats( | |
290 stats.cast_to<RTCPeerConnectionStats>()); | |
291 } else if (stats.type() == RTCInboundRTPStreamStats::kType) { | |
292 verify_successful &= VerifyRTCInboundRTPStreamStats( | |
293 stats.cast_to<RTCInboundRTPStreamStats>()); | |
294 } else if (stats.type() == RTCOutboundRTPStreamStats::kType) { | |
295 verify_successful &= VerifyRTCOutboundRTPStreamStats( | |
296 stats.cast_to<RTCOutboundRTPStreamStats>()); | |
297 } else if (stats.type() == RTCTransportStats::kType) { | |
298 verify_successful &= VerifyRTCTransportStats( | |
299 stats.cast_to<RTCTransportStats>()); | |
300 } else { | |
301 EXPECT_TRUE(false) << "Unrecognized stats type: " << stats.type(); | |
302 verify_successful = false; | |
303 } | |
304 } | |
305 if (!missing_stats.empty()) { | |
306 verify_successful = false; | |
307 for (const char* missing : missing_stats) { | |
308 EXPECT_TRUE(false) << "Missing expected stats type: " << missing; | |
309 } | |
310 } | |
311 EXPECT_TRUE(verify_successful) << | |
312 "One or more problems with the stats. This is the report:\n" << | |
313 report_->ToString(); | |
314 } | |
315 | |
316 bool VerifyRTCCertificateStats( | |
317 const RTCCertificateStats& certificate) { | |
318 RTCStatsVerifier verifier(report_, &certificate); | |
319 verifier.TestMemberIsDefined(certificate.fingerprint); | |
320 verifier.TestMemberIsDefined(certificate.fingerprint_algorithm); | |
321 verifier.TestMemberIsDefined(certificate.base64_certificate); | |
322 verifier.TestMemberIsOptionalIDReference( | |
323 certificate.issuer_certificate_id, RTCCertificateStats::kType); | |
324 return verifier.ExpectAllMembersSuccessfullyTested(); | |
325 } | |
326 | |
327 bool VerifyRTCCodecStats( | |
328 const RTCCodecStats& codec) { | |
329 RTCStatsVerifier verifier(report_, &codec); | |
330 verifier.TestMemberIsDefined(codec.payload_type); | |
331 verifier.TestMemberIsDefined(codec.codec); | |
332 verifier.TestMemberIsPositive<uint32_t>(codec.clock_rate); | |
333 verifier.TestMemberIsUndefined(codec.channels); | |
334 verifier.TestMemberIsUndefined(codec.parameters); | |
335 verifier.TestMemberIsUndefined(codec.implementation); | |
336 return verifier.ExpectAllMembersSuccessfullyTested(); | |
337 } | |
338 | |
339 bool VerifyRTCDataChannelStats( | |
340 const RTCDataChannelStats& data_channel) { | |
341 RTCStatsVerifier verifier(report_, &data_channel); | |
342 verifier.TestMemberIsDefined(data_channel.label); | |
343 verifier.TestMemberIsDefined(data_channel.protocol); | |
344 verifier.TestMemberIsDefined(data_channel.datachannelid); | |
345 verifier.TestMemberIsDefined(data_channel.state); | |
346 verifier.TestMemberIsNonNegative<uint32_t>(data_channel.messages_sent); | |
347 verifier.TestMemberIsNonNegative<uint64_t>(data_channel.bytes_sent); | |
348 verifier.TestMemberIsNonNegative<uint32_t>(data_channel.messages_received); | |
349 verifier.TestMemberIsNonNegative<uint64_t>(data_channel.bytes_received); | |
350 return verifier.ExpectAllMembersSuccessfullyTested(); | |
351 } | |
352 | |
353 bool VerifyRTCIceCandidatePairStats( | |
354 const RTCIceCandidatePairStats& candidate_pair) { | |
355 RTCStatsVerifier verifier(report_, &candidate_pair); | |
356 verifier.TestMemberIsIDReference( | |
357 candidate_pair.transport_id, RTCTransportStats::kType); | |
358 verifier.TestMemberIsIDReference( | |
359 candidate_pair.local_candidate_id, RTCLocalIceCandidateStats::kType); | |
360 verifier.TestMemberIsIDReference( | |
361 candidate_pair.remote_candidate_id, RTCRemoteIceCandidateStats::kType); | |
362 verifier.TestMemberIsDefined(candidate_pair.state); | |
363 verifier.TestMemberIsNonNegative<uint64_t>(candidate_pair.priority); | |
364 verifier.TestMemberIsUndefined(candidate_pair.nominated); | |
365 verifier.TestMemberIsDefined(candidate_pair.writable); | |
366 verifier.TestMemberIsUndefined(candidate_pair.readable); | |
367 verifier.TestMemberIsNonNegative<uint64_t>(candidate_pair.bytes_sent); | |
368 verifier.TestMemberIsNonNegative<uint64_t>(candidate_pair.bytes_received); | |
369 verifier.TestMemberIsUndefined(candidate_pair.total_round_trip_time); | |
370 verifier.TestMemberIsNonNegative<double>( | |
371 candidate_pair.current_round_trip_time); | |
372 verifier.TestMemberIsUndefined(candidate_pair.available_outgoing_bitrate); | |
373 verifier.TestMemberIsUndefined(candidate_pair.available_incoming_bitrate); | |
374 verifier.TestMemberIsNonNegative<uint64_t>( | |
375 candidate_pair.requests_received); | |
376 verifier.TestMemberIsNonNegative<uint64_t>(candidate_pair.requests_sent); | |
377 verifier.TestMemberIsNonNegative<uint64_t>( | |
378 candidate_pair.responses_received); | |
379 verifier.TestMemberIsNonNegative<uint64_t>(candidate_pair.responses_sent); | |
380 verifier.TestMemberIsUndefined(candidate_pair.retransmissions_received); | |
381 verifier.TestMemberIsUndefined(candidate_pair.retransmissions_sent); | |
382 verifier.TestMemberIsUndefined(candidate_pair.consent_requests_received); | |
383 verifier.TestMemberIsNonNegative<uint64_t>( | |
384 candidate_pair.consent_requests_sent); | |
385 verifier.TestMemberIsUndefined(candidate_pair.consent_responses_received); | |
386 verifier.TestMemberIsUndefined(candidate_pair.consent_responses_sent); | |
387 return verifier.ExpectAllMembersSuccessfullyTested(); | |
388 } | |
389 | |
390 bool VerifyRTCIceCandidateStats( | |
391 const RTCIceCandidateStats& candidate) { | |
392 RTCStatsVerifier verifier(report_, &candidate); | |
393 verifier.TestMemberIsIDReference( | |
394 candidate.transport_id, RTCTransportStats::kType); | |
395 verifier.TestMemberIsDefined(candidate.is_remote); | |
396 verifier.TestMemberIsDefined(candidate.ip); | |
397 verifier.TestMemberIsNonNegative<int32_t>(candidate.port); | |
398 verifier.TestMemberIsDefined(candidate.protocol); | |
399 verifier.TestMemberIsDefined(candidate.candidate_type); | |
400 verifier.TestMemberIsNonNegative<int32_t>(candidate.priority); | |
401 verifier.TestMemberIsUndefined(candidate.url); | |
402 verifier.TestMemberIsDefined(candidate.deleted); | |
403 return verifier.ExpectAllMembersSuccessfullyTested(); | |
404 } | |
405 | |
406 bool VerifyRTCLocalIceCandidateStats( | |
407 const RTCLocalIceCandidateStats& local_candidate) { | |
408 return VerifyRTCIceCandidateStats(local_candidate); | |
409 } | |
410 | |
411 bool VerifyRTCRemoteIceCandidateStats( | |
412 const RTCRemoteIceCandidateStats& remote_candidate) { | |
413 return VerifyRTCIceCandidateStats(remote_candidate); | |
414 } | |
415 | |
416 bool VerifyRTCMediaStreamStats( | |
417 const RTCMediaStreamStats& media_stream) { | |
418 RTCStatsVerifier verifier(report_, &media_stream); | |
419 verifier.TestMemberIsDefined(media_stream.stream_identifier); | |
420 verifier.TestMemberIsIDReference( | |
421 media_stream.track_ids, RTCMediaStreamTrackStats::kType); | |
422 return verifier.ExpectAllMembersSuccessfullyTested(); | |
423 } | |
424 | |
425 bool VerifyRTCMediaStreamTrackStats( | |
426 const RTCMediaStreamTrackStats& media_stream_track) { | |
427 RTCStatsVerifier verifier(report_, &media_stream_track); | |
428 verifier.TestMemberIsDefined(media_stream_track.track_identifier); | |
429 verifier.TestMemberIsDefined(media_stream_track.remote_source); | |
430 verifier.TestMemberIsDefined(media_stream_track.ended); | |
431 verifier.TestMemberIsDefined(media_stream_track.detached); | |
432 verifier.TestMemberIsDefined(media_stream_track.kind); | |
433 // Video or audio media stream track? | |
434 if (*media_stream_track.kind == RTCMediaStreamTrackKind::kVideo) { | |
435 // Video-only members | |
436 verifier.TestMemberIsNonNegative<uint32_t>( | |
437 media_stream_track.frame_width); | |
438 verifier.TestMemberIsNonNegative<uint32_t>( | |
439 media_stream_track.frame_height); | |
440 verifier.TestMemberIsUndefined(media_stream_track.frames_per_second); | |
441 if (*media_stream_track.remote_source) { | |
442 verifier.TestMemberIsUndefined(media_stream_track.frames_sent); | |
443 verifier.TestMemberIsNonNegative<uint32_t>( | |
444 media_stream_track.frames_received); | |
445 verifier.TestMemberIsNonNegative<uint32_t>( | |
446 media_stream_track.frames_decoded); | |
447 } else { | |
448 verifier.TestMemberIsNonNegative<uint32_t>( | |
449 media_stream_track.frames_sent); | |
450 verifier.TestMemberIsUndefined(media_stream_track.frames_received); | |
451 verifier.TestMemberIsUndefined(media_stream_track.frames_decoded); | |
452 } | |
453 verifier.TestMemberIsUndefined(media_stream_track.frames_dropped); | |
454 verifier.TestMemberIsUndefined(media_stream_track.frames_corrupted); | |
455 verifier.TestMemberIsUndefined(media_stream_track.partial_frames_lost); | |
456 verifier.TestMemberIsUndefined(media_stream_track.full_frames_lost); | |
457 // Audio-only members should be undefined | |
458 verifier.TestMemberIsUndefined(media_stream_track.audio_level); | |
459 verifier.TestMemberIsUndefined(media_stream_track.echo_return_loss); | |
460 verifier.TestMemberIsUndefined( | |
461 media_stream_track.echo_return_loss_enhancement); | |
462 } else { | |
463 RTC_DCHECK_EQ(*media_stream_track.kind, | |
464 RTCMediaStreamTrackKind::kAudio); | |
465 // Video-only members should be undefined | |
466 verifier.TestMemberIsUndefined(media_stream_track.frame_width); | |
467 verifier.TestMemberIsUndefined(media_stream_track.frame_height); | |
468 verifier.TestMemberIsUndefined(media_stream_track.frames_per_second); | |
469 verifier.TestMemberIsUndefined(media_stream_track.frames_sent); | |
470 verifier.TestMemberIsUndefined(media_stream_track.frames_received); | |
471 verifier.TestMemberIsUndefined(media_stream_track.frames_decoded); | |
472 verifier.TestMemberIsUndefined(media_stream_track.frames_dropped); | |
473 verifier.TestMemberIsUndefined(media_stream_track.frames_corrupted); | |
474 verifier.TestMemberIsUndefined(media_stream_track.partial_frames_lost); | |
475 verifier.TestMemberIsUndefined(media_stream_track.full_frames_lost); | |
476 // Audio-only members | |
477 verifier.TestMemberIsNonNegative<double>(media_stream_track.audio_level); | |
478 // TODO(hbos): |echo_return_loss| and |echo_return_loss_enhancement| are | |
479 // flaky on msan bot (sometimes defined, sometimes undefined). Should the | |
480 // test run until available or is there a way to have it always be | |
481 // defined? crbug.com/627816 | |
482 verifier.MarkMemberTested(media_stream_track.echo_return_loss, true); | |
483 verifier.MarkMemberTested( | |
484 media_stream_track.echo_return_loss_enhancement, true); | |
485 } | |
486 return verifier.ExpectAllMembersSuccessfullyTested(); | |
487 } | |
488 | |
489 bool VerifyRTCPeerConnectionStats( | |
490 const RTCPeerConnectionStats& peer_connection) { | |
491 RTCStatsVerifier verifier(report_, &peer_connection); | |
492 verifier.TestMemberIsNonNegative<uint32_t>( | |
493 peer_connection.data_channels_opened); | |
494 verifier.TestMemberIsNonNegative<uint32_t>( | |
495 peer_connection.data_channels_closed); | |
496 return verifier.ExpectAllMembersSuccessfullyTested(); | |
497 } | |
498 | |
499 void VerifyRTCRTPStreamStats( | |
500 const RTCRTPStreamStats& stream, RTCStatsVerifier* verifier) { | |
501 verifier->TestMemberIsDefined(stream.ssrc); | |
502 verifier->TestMemberIsUndefined(stream.associate_stats_id); | |
503 verifier->TestMemberIsDefined(stream.is_remote); | |
504 verifier->TestMemberIsDefined(stream.media_type); | |
505 verifier->TestMemberIsIDReference( | |
506 stream.media_track_id, RTCMediaStreamTrackStats::kType); | |
507 verifier->TestMemberIsIDReference( | |
508 stream.transport_id, RTCTransportStats::kType); | |
509 verifier->TestMemberIsIDReference(stream.codec_id, RTCCodecStats::kType); | |
510 if (stream.media_type.is_defined() && *stream.media_type == "video") { | |
511 verifier->TestMemberIsNonNegative<uint32_t>(stream.fir_count); | |
512 verifier->TestMemberIsNonNegative<uint32_t>(stream.pli_count); | |
513 verifier->TestMemberIsNonNegative<uint32_t>(stream.nack_count); | |
514 } else { | |
515 verifier->TestMemberIsUndefined(stream.fir_count); | |
516 verifier->TestMemberIsUndefined(stream.pli_count); | |
517 verifier->TestMemberIsUndefined(stream.nack_count); | |
518 } | |
519 verifier->TestMemberIsUndefined(stream.sli_count); | |
520 } | |
521 | |
522 bool VerifyRTCInboundRTPStreamStats( | |
523 const RTCInboundRTPStreamStats& inbound_stream) { | |
524 RTCStatsVerifier verifier(report_, &inbound_stream); | |
525 VerifyRTCRTPStreamStats(inbound_stream, &verifier); | |
526 verifier.TestMemberIsUndefined(inbound_stream.qp_sum); | |
527 verifier.TestMemberIsNonNegative<uint32_t>(inbound_stream.packets_received); | |
528 verifier.TestMemberIsNonNegative<uint64_t>(inbound_stream.bytes_received); | |
529 verifier.TestMemberIsNonNegative<uint32_t>(inbound_stream.packets_lost); | |
530 if (inbound_stream.media_type.is_defined() && | |
531 *inbound_stream.media_type == "video") { | |
532 verifier.TestMemberIsUndefined(inbound_stream.jitter); | |
533 } else { | |
534 verifier.TestMemberIsNonNegative<double>(inbound_stream.jitter); | |
535 } | |
536 verifier.TestMemberIsNonNegative<double>(inbound_stream.fraction_lost); | |
537 verifier.TestMemberIsUndefined(inbound_stream.packets_discarded); | |
538 verifier.TestMemberIsUndefined(inbound_stream.packets_repaired); | |
539 verifier.TestMemberIsUndefined(inbound_stream.burst_packets_lost); | |
540 verifier.TestMemberIsUndefined(inbound_stream.burst_packets_discarded); | |
541 verifier.TestMemberIsUndefined(inbound_stream.burst_loss_count); | |
542 verifier.TestMemberIsUndefined(inbound_stream.burst_discard_count); | |
543 verifier.TestMemberIsUndefined(inbound_stream.burst_loss_rate); | |
544 verifier.TestMemberIsUndefined(inbound_stream.burst_discard_rate); | |
545 verifier.TestMemberIsUndefined(inbound_stream.gap_loss_rate); | |
546 verifier.TestMemberIsUndefined(inbound_stream.gap_discard_rate); | |
547 if (inbound_stream.media_type.is_defined() && | |
548 *inbound_stream.media_type == "video") { | |
549 verifier.TestMemberIsDefined(inbound_stream.frames_decoded); | |
550 } else { | |
551 verifier.TestMemberIsUndefined(inbound_stream.frames_decoded); | |
552 } | |
553 return verifier.ExpectAllMembersSuccessfullyTested(); | |
554 } | |
555 | |
556 bool VerifyRTCOutboundRTPStreamStats( | |
557 const RTCOutboundRTPStreamStats& outbound_stream) { | |
558 RTCStatsVerifier verifier(report_, &outbound_stream); | |
559 VerifyRTCRTPStreamStats(outbound_stream, &verifier); | |
560 if (outbound_stream.media_type.is_defined() && | |
561 *outbound_stream.media_type == "video") { | |
562 verifier.TestMemberIsNonNegative<uint64_t>(outbound_stream.qp_sum); | |
563 } else { | |
564 verifier.TestMemberIsUndefined(outbound_stream.qp_sum); | |
565 } | |
566 verifier.TestMemberIsNonNegative<uint32_t>(outbound_stream.packets_sent); | |
567 verifier.TestMemberIsNonNegative<uint64_t>(outbound_stream.bytes_sent); | |
568 verifier.TestMemberIsUndefined(outbound_stream.target_bitrate); | |
569 // TODO(hbos): Defined in video but not audio case. Why? crbug.com/669877 | |
570 verifier.MarkMemberTested(outbound_stream.round_trip_time, true); | |
571 if (outbound_stream.media_type.is_defined() && | |
572 *outbound_stream.media_type == "video") { | |
573 verifier.TestMemberIsDefined(outbound_stream.frames_encoded); | |
574 } else { | |
575 verifier.TestMemberIsUndefined(outbound_stream.frames_encoded); | |
576 } | |
577 return verifier.ExpectAllMembersSuccessfullyTested(); | |
578 } | |
579 | |
580 bool VerifyRTCTransportStats( | |
581 const RTCTransportStats& transport) { | |
582 RTCStatsVerifier verifier(report_, &transport); | |
583 verifier.TestMemberIsNonNegative<uint64_t>(transport.bytes_sent); | |
584 verifier.TestMemberIsNonNegative<uint64_t>(transport.bytes_received); | |
585 verifier.TestMemberIsOptionalIDReference( | |
586 transport.rtcp_transport_stats_id, RTCTransportStats::kType); | |
587 verifier.TestMemberIsDefined(transport.dtls_state); | |
588 verifier.TestMemberIsIDReference( | |
589 transport.selected_candidate_pair_id, RTCIceCandidatePairStats::kType); | |
590 verifier.TestMemberIsIDReference( | |
591 transport.local_certificate_id, RTCCertificateStats::kType); | |
592 verifier.TestMemberIsIDReference( | |
593 transport.remote_certificate_id, RTCCertificateStats::kType); | |
594 return verifier.ExpectAllMembersSuccessfullyTested(); | |
595 } | |
596 | |
597 private: | |
598 rtc::scoped_refptr<const RTCStatsReport> report_; | |
599 }; | |
600 | |
601 #ifdef HAVE_SCTP | |
602 TEST_F(RTCStatsIntegrationTest, GetStatsFromCaller) { | |
603 StartCall(); | |
604 | |
605 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsFromCaller(); | |
606 RTCStatsReportVerifier(report.get()).VerifyReport(); | |
607 } | |
608 | |
609 TEST_F(RTCStatsIntegrationTest, GetStatsFromCallee) { | |
610 StartCall(); | |
611 | |
612 rtc::scoped_refptr<const RTCStatsReport> report = GetStatsFromCallee(); | |
613 RTCStatsReportVerifier(report.get()).VerifyReport(); | |
614 } | |
615 | |
616 TEST_F(RTCStatsIntegrationTest, GetsStatsWhileDestroyingPeerConnections) { | |
617 StartCall(); | |
618 | |
619 rtc::scoped_refptr<RTCStatsObtainer> stats_obtainer = | |
620 RTCStatsObtainer::Create(); | |
621 caller_->pc()->GetStats(stats_obtainer); | |
622 // This will destroy the peer connection. | |
623 caller_ = nullptr; | |
624 // Any pending stats requests should have completed in the act of destroying | |
625 // the peer connection. | |
626 EXPECT_TRUE(stats_obtainer->report()); | |
627 } | |
628 #endif // HAVE_SCTP | |
629 | |
630 } // namespace | |
631 | |
632 } // namespace webrtc | |
OLD | NEW |