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) {