pc: invalidate stats cache when firing onicecandidate
https://w3c.github.io/webrtc-stats/#guidelines-for-getstats-results-caching-throttling
"When the state of the RTCPeerConnection visibly changes as a result of an API call, a promise resolving or an event firing, subsequent new getStats() calls must return up-to-date dictionaries for the affected objects."
BUG=webrtc:14190
Change-Id: I4560be22795f30e0369d573bda0100e490efb57b
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/265870
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Commit-Queue: Philipp Hancke <philipp.hancke@googlemail.com>
Cr-Commit-Position: refs/heads/main@{#37255}
diff --git a/pc/peer_connection.cc b/pc/peer_connection.cc
index 557f2e6..11004ba 100644
--- a/pc/peer_connection.cc
+++ b/pc/peer_connection.cc
@@ -2000,6 +2000,7 @@
return;
}
ReportIceCandidateCollected(candidate->candidate());
+ ClearStatsCache();
Observer()->OnIceCandidate(candidate.get());
}
diff --git a/pc/peer_connection_integrationtest.cc b/pc/peer_connection_integrationtest.cc
index 9811392..d6ac0c8 100644
--- a/pc/peer_connection_integrationtest.cc
+++ b/pc/peer_connection_integrationtest.cc
@@ -2418,6 +2418,38 @@
ClosePeerConnections();
}
+TEST_P(PeerConnectionIntegrationTestWithFakeClock,
+ OnIceCandidateFlushesGetStatsCache) {
+ ASSERT_TRUE(CreatePeerConnectionWrappers());
+ ConnectFakeSignaling();
+ caller()->AddAudioTrack();
+
+ // Call getStats, assert there are no candidates.
+ rtc::scoped_refptr<const webrtc::RTCStatsReport> first_report =
+ caller()->NewGetStats();
+ ASSERT_TRUE(first_report);
+ auto first_candidate_stats =
+ first_report->GetStatsOfType<webrtc::RTCLocalIceCandidateStats>();
+ ASSERT_EQ(first_candidate_stats.size(), 0u);
+
+ // Start candidate gathering and wait for it to complete.
+ caller()->CreateAndSetAndSignalOffer();
+ ASSERT_TRUE_SIMULATED_WAIT(caller()->IceGatheringStateComplete(),
+ kDefaultTimeout, FakeClock());
+
+ // Call getStats again, assert there are candidates now.
+ rtc::scoped_refptr<const webrtc::RTCStatsReport> second_report =
+ caller()->NewGetStats();
+ ASSERT_TRUE(second_report);
+ auto second_candidate_stats =
+ second_report->GetStatsOfType<webrtc::RTCLocalIceCandidateStats>();
+ ASSERT_NE(second_candidate_stats.size(), 0u);
+
+ // The fake clock ensures that no time has passed so the cache must have been
+ // explicitly invalidated.
+ EXPECT_EQ(first_report->timestamp_us(), second_report->timestamp_us());
+}
+
#endif // !defined(THREAD_SANITIZER)
// Verify that a TurnCustomizer passed in through RTCConfiguration
diff --git a/pc/test/integration_test_helpers.h b/pc/test/integration_test_helpers.h
index 53df9fc..460148c 100644
--- a/pc/test/integration_test_helpers.h
+++ b/pc/test/integration_test_helpers.h
@@ -410,6 +410,11 @@
return pc()->signaling_state() == webrtc::PeerConnectionInterface::kStable;
}
+ bool IceGatheringStateComplete() {
+ return pc()->ice_gathering_state() ==
+ webrtc::PeerConnectionInterface::kIceGatheringComplete;
+ }
+
void CreateDataChannel() { CreateDataChannel(nullptr); }
void CreateDataChannel(const webrtc::DataChannelInit* init) {