diff --git a/api/peerconnectioninterface.h b/api/peerconnectioninterface.h index 4851206cb4..edac135cf1 100644 --- a/api/peerconnectioninterface.h +++ b/api/peerconnectioninterface.h @@ -1098,6 +1098,14 @@ class PeerConnectionObserver { // TODO(hbos,deadbeef): Make pure virtual when all subclasses implement it. virtual void OnRemoveTrack( rtc::scoped_refptr receiver) {} + + // Called when an interesting usage is detected by WebRTC. + // An appropriate action is to add information about the context of the + // PeerConnection and write the event to some kind of "interesting events" + // log function. + // The heuristics for defining what constitutes "interesting" are + // implementation-defined. + virtual void OnInterestingUsage(int usage_pattern) {} }; // PeerConnectionDependencies holds all of PeerConnections dependencies. diff --git a/pc/peerconnection.cc b/pc/peerconnection.cc index 6edc19ac79..9f38a5dcfc 100644 --- a/pc/peerconnection.cc +++ b/pc/peerconnection.cc @@ -5948,6 +5948,17 @@ void PeerConnection::ReportUsagePattern() const { RTC_HISTOGRAM_ENUMERATION_SPARSE("WebRTC.PeerConnection.UsagePattern", usage_event_accumulator_, static_cast(UsageEvent::MAX_VALUE)); + const int bad_bits = + static_cast(UsageEvent::SET_LOCAL_DESCRIPTION_CALLED) | + static_cast(UsageEvent::CANDIDATE_COLLECTED); + const int good_bits = + static_cast(UsageEvent::SET_REMOTE_DESCRIPTION_CALLED) | + static_cast(UsageEvent::REMOTE_CANDIDATE_ADDED) | + static_cast(UsageEvent::ICE_STATE_CONNECTED); + if ((usage_event_accumulator_ & bad_bits) == bad_bits && + (usage_event_accumulator_ & good_bits) == 0) { + observer_->OnInterestingUsage(usage_event_accumulator_); + } } void PeerConnection::ReportNegotiatedSdpSemantics( diff --git a/pc/peerconnection_histogram_unittest.cc b/pc/peerconnection_histogram_unittest.cc index 0067cd6ef9..f40f96c99f 100644 --- a/pc/peerconnection_histogram_unittest.cc +++ b/pc/peerconnection_histogram_unittest.cc @@ -32,6 +32,7 @@ using RTCConfiguration = PeerConnectionInterface::RTCConfiguration; using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions; using ::testing::Values; +static const char kUsagePatternMetric[] = "WebRTC.PeerConnection.UsagePattern"; static constexpr int kDefaultTimeout = 10000; static const rtc::SocketAddress kDefaultLocalAddress("1.1.1.1", 0); static const rtc::SocketAddress kPrivateLocalAddress("10.1.1.1", 0); @@ -75,12 +76,23 @@ typedef PeerConnectionWrapperForUsageHistogramTest* RawWrapperPtr; class ObserverForUsageHistogramTest : public MockPeerConnectionObserver { public: void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) override; + + void OnInterestingUsage(int usage_pattern) override { + interesting_usage_detected_ = usage_pattern; + } + void PrepareToExchangeCandidates(RawWrapperPtr other) { candidate_target_ = other; } + bool HaveDataChannel() { return last_datachannel_; } + absl::optional interesting_usage_detected() { + return interesting_usage_detected_; + } + private: + absl::optional interesting_usage_detected_; RawWrapperPtr candidate_target_; // Note: Not thread-safe against deletions. }; @@ -96,12 +108,16 @@ class PeerConnectionWrapperForUsageHistogramTest return static_cast(pci->internal()); } + // Override with different return type + ObserverForUsageHistogramTest* observer() { + return static_cast( + PeerConnectionWrapper::observer()); + } + void PrepareToExchangeCandidates( PeerConnectionWrapperForUsageHistogramTest* other) { - static_cast(observer()) - ->PrepareToExchangeCandidates(other); - static_cast(other->observer()) - ->PrepareToExchangeCandidates(this); + observer()->PrepareToExchangeCandidates(other); + other->observer()->PrepareToExchangeCandidates(this); } bool IsConnected() { @@ -237,6 +253,13 @@ class PeerConnectionUsageHistogramTest : public ::testing::Test { return wrapper; } + int ObservedFingerprint() { + // This works correctly only if there is only one sample value + // that has been counted. + // Returns -1 for "not found". + return webrtc::metrics::MinSample(kUsagePatternMetric); + } + std::unique_ptr fake_network_manager_; std::unique_ptr vss_; rtc::AutoSocketServerThread main_; @@ -246,11 +269,10 @@ TEST_F(PeerConnectionUsageHistogramTest, UsageFingerprintHistogramFromTimeout) { auto pc = CreatePeerConnectionWithImmediateReport(); int expected_fingerprint = MakeUsageFingerprint({}); - ASSERT_TRUE_WAIT( - 1u == webrtc::metrics::NumSamples("WebRTC.PeerConnection.UsagePattern"), - kDefaultTimeout); - EXPECT_EQ(1, webrtc::metrics::NumEvents("WebRTC.PeerConnection.UsagePattern", - expected_fingerprint)); + ASSERT_EQ_WAIT(1, webrtc::metrics::NumSamples(kUsagePatternMetric), + kDefaultTimeout); + EXPECT_EQ( + 1, webrtc::metrics::NumEvents(kUsagePatternMetric, expected_fingerprint)); } #ifndef WEBRTC_ANDROID @@ -277,13 +299,12 @@ TEST_F(PeerConnectionUsageHistogramTest, FingerprintAudioVideo) { PeerConnection::UsageEvent::CLOSE_CALLED}); // In this case, we may or may not have PRIVATE_CANDIDATE_COLLECTED, // depending on the machine configuration. - EXPECT_EQ(2, - webrtc::metrics::NumSamples("WebRTC.PeerConnection.UsagePattern")); + EXPECT_EQ(2, webrtc::metrics::NumSamples(kUsagePatternMetric)); EXPECT_TRUE( - webrtc::metrics::NumEvents("WebRTC.PeerConnection.UsagePattern", - expected_fingerprint) == 2 || + webrtc::metrics::NumEvents(kUsagePatternMetric, expected_fingerprint) == + 2 || webrtc::metrics::NumEvents( - "WebRTC.PeerConnection.UsagePattern", + kUsagePatternMetric, expected_fingerprint | static_cast( PeerConnection::UsageEvent::PRIVATE_CANDIDATE_COLLECTED)) == @@ -315,10 +336,9 @@ TEST_F(PeerConnectionUsageHistogramTest, FingerprintWithNoHostCandidates) { PeerConnection::UsageEvent::REMOTE_CANDIDATE_ADDED, PeerConnection::UsageEvent::ICE_STATE_CONNECTED, PeerConnection::UsageEvent::CLOSE_CALLED}); - EXPECT_EQ(2, - webrtc::metrics::NumSamples("WebRTC.PeerConnection.UsagePattern")); - EXPECT_EQ(2, webrtc::metrics::NumEvents("WebRTC.PeerConnection.UsagePattern", - expected_fingerprint)); + EXPECT_EQ(2, webrtc::metrics::NumSamples(kUsagePatternMetric)); + EXPECT_EQ( + 2, webrtc::metrics::NumEvents(kUsagePatternMetric, expected_fingerprint)); } #ifdef HAVE_SCTP @@ -338,13 +358,12 @@ TEST_F(PeerConnectionUsageHistogramTest, FingerprintDataOnly) { PeerConnection::UsageEvent::REMOTE_CANDIDATE_ADDED, PeerConnection::UsageEvent::ICE_STATE_CONNECTED, PeerConnection::UsageEvent::CLOSE_CALLED}); - EXPECT_EQ(2, - webrtc::metrics::NumSamples("WebRTC.PeerConnection.UsagePattern")); + EXPECT_EQ(2, webrtc::metrics::NumSamples(kUsagePatternMetric)); EXPECT_TRUE( - webrtc::metrics::NumEvents("WebRTC.PeerConnection.UsagePattern", - expected_fingerprint) == 2 || + webrtc::metrics::NumEvents(kUsagePatternMetric, expected_fingerprint) == + 2 || webrtc::metrics::NumEvents( - "WebRTC.PeerConnection.UsagePattern", + kUsagePatternMetric, expected_fingerprint | static_cast( PeerConnection::UsageEvent::PRIVATE_CANDIDATE_COLLECTED)) == @@ -369,10 +388,9 @@ TEST_F(PeerConnectionUsageHistogramTest, FingerprintStunTurn) { MakeUsageFingerprint({PeerConnection::UsageEvent::STUN_SERVER_ADDED, PeerConnection::UsageEvent::TURN_SERVER_ADDED, PeerConnection::UsageEvent::CLOSE_CALLED}); - EXPECT_EQ(1, - webrtc::metrics::NumSamples("WebRTC.PeerConnection.UsagePattern")); - EXPECT_EQ(1, webrtc::metrics::NumEvents("WebRTC.PeerConnection.UsagePattern", - expected_fingerprint)); + EXPECT_EQ(1, webrtc::metrics::NumSamples(kUsagePatternMetric)); + EXPECT_EQ( + 1, webrtc::metrics::NumEvents(kUsagePatternMetric, expected_fingerprint)); } TEST_F(PeerConnectionUsageHistogramTest, FingerprintStunTurnInReconfiguration) { @@ -394,10 +412,9 @@ TEST_F(PeerConnectionUsageHistogramTest, FingerprintStunTurnInReconfiguration) { MakeUsageFingerprint({PeerConnection::UsageEvent::STUN_SERVER_ADDED, PeerConnection::UsageEvent::TURN_SERVER_ADDED, PeerConnection::UsageEvent::CLOSE_CALLED}); - EXPECT_EQ(1, - webrtc::metrics::NumSamples("WebRTC.PeerConnection.UsagePattern")); - EXPECT_EQ(1, webrtc::metrics::NumEvents("WebRTC.PeerConnection.UsagePattern", - expected_fingerprint)); + EXPECT_EQ(1, webrtc::metrics::NumSamples(kUsagePatternMetric)); + EXPECT_EQ( + 1, webrtc::metrics::NumEvents(kUsagePatternMetric, expected_fingerprint)); } TEST_F(PeerConnectionUsageHistogramTest, FingerprintWithPrivateIP) { @@ -411,10 +428,33 @@ TEST_F(PeerConnectionUsageHistogramTest, FingerprintWithPrivateIP) { PeerConnection::UsageEvent::CANDIDATE_COLLECTED, PeerConnection::UsageEvent::CLOSE_CALLED, PeerConnection::UsageEvent::PRIVATE_CANDIDATE_COLLECTED}); - EXPECT_EQ(1, - webrtc::metrics::NumSamples("WebRTC.PeerConnection.UsagePattern")); - EXPECT_EQ(1, webrtc::metrics::NumEvents("WebRTC.PeerConnection.UsagePattern", - expected_fingerprint)); + EXPECT_EQ(1, webrtc::metrics::NumSamples(kUsagePatternMetric)); + EXPECT_EQ( + 1, webrtc::metrics::NumEvents(kUsagePatternMetric, expected_fingerprint)); } +#ifndef WEBRTC_ANDROID +#ifdef HAVE_SCTP +TEST_F(PeerConnectionUsageHistogramTest, NotableUsageNoted) { + auto caller = CreatePeerConnection(); + caller->CreateDataChannel("foo"); + caller->GenerateOfferAndCollectCandidates(); + caller->pc()->Close(); + int expected_fingerprint = MakeUsageFingerprint( + {PeerConnection::UsageEvent::DATA_ADDED, + PeerConnection::UsageEvent::SET_LOCAL_DESCRIPTION_CALLED, + PeerConnection::UsageEvent::CANDIDATE_COLLECTED, + PeerConnection::UsageEvent::CLOSE_CALLED}); + EXPECT_EQ(1, webrtc::metrics::NumSamples(kUsagePatternMetric)); + EXPECT_TRUE(expected_fingerprint == ObservedFingerprint() || + (expected_fingerprint | + static_cast( + PeerConnection::UsageEvent::PRIVATE_CANDIDATE_COLLECTED)) == + ObservedFingerprint()); + EXPECT_EQ(absl::make_optional(ObservedFingerprint()), + caller->observer()->interesting_usage_detected()); +} +#endif +#endif + } // namespace webrtc