diff --git a/api/BUILD.gn b/api/BUILD.gn index f54766a32b..a0a9563ce0 100644 --- a/api/BUILD.gn +++ b/api/BUILD.gn @@ -474,6 +474,7 @@ rtc_source_set("video_quality_analyzer_api") { deps = [ ":array_view", ":stats_observer_interface", + "../rtc_base:checks", "video:encoded_image", "video:video_frame", "video:video_rtp_headers", diff --git a/api/test/video_quality_analyzer_interface.h b/api/test/video_quality_analyzer_interface.h index 1ea59f731c..d21bc6c5f7 100644 --- a/api/test/video_quality_analyzer_interface.h +++ b/api/test/video_quality_analyzer_interface.h @@ -21,6 +21,7 @@ #include "api/video/encoded_image.h" #include "api/video/video_frame.h" #include "api/video_codecs/video_encoder.h" +#include "rtc_base/checks.h" namespace webrtc { @@ -170,6 +171,13 @@ class VideoQualityAnalyzerInterface // frame ids space wraps around, then stream label for frame id may change. // It will crash, if the specified `frame_id` wasn't captured. virtual std::string GetStreamLabel(uint16_t frame_id) = 0; + + // Returns the sender peer name of the last stream where this frame was + // captured. The sender for this frame id may change when the frame ids wrap + // around. Also it will crash, if the specified `frame_id` wasn't captured. + virtual std::string GetSenderPeerName(uint16_t frame_id) const { + RTC_CHECK(false) << "Not implemented."; + } }; } // namespace webrtc diff --git a/test/pc/e2e/analyzer/video/default_video_quality_analyzer.cc b/test/pc/e2e/analyzer/video/default_video_quality_analyzer.cc index a8381ce128..2c81c5dc05 100644 --- a/test/pc/e2e/analyzer/video/default_video_quality_analyzer.cc +++ b/test/pc/e2e/analyzer/video/default_video_quality_analyzer.cc @@ -843,19 +843,17 @@ void DefaultVideoQualityAnalyzer::Stop() { } std::string DefaultVideoQualityAnalyzer::GetStreamLabel(uint16_t frame_id) { - MutexLock lock1(&mutex_); - auto it = captured_frames_in_flight_.find(frame_id); - if (it != captured_frames_in_flight_.end()) { - return streams_.name(it->second.stream()); - } - for (auto hist_it = stream_to_frame_id_history_.begin(); - hist_it != stream_to_frame_id_history_.end(); ++hist_it) { - auto hist_set_it = hist_it->second.find(frame_id); - if (hist_set_it != hist_it->second.end()) { - return streams_.name(hist_it->first); - } - } - RTC_CHECK(false) << "Unknown frame_id=" << frame_id; + MutexLock lock(&mutex_); + return GetStreamLabelInternal(frame_id); +} + +std::string DefaultVideoQualityAnalyzer::GetSenderPeerName( + uint16_t frame_id) const { + MutexLock lock(&mutex_); + std::string stream_label = GetStreamLabelInternal(frame_id); + size_t stream_index = streams_.index(stream_label); + size_t sender_peer_index = stream_states_.at(stream_index).sender(); + return peers_->name(sender_peer_index); } std::set DefaultVideoQualityAnalyzer::GetKnownVideoStreams() const { @@ -1321,6 +1319,22 @@ std::string DefaultVideoQualityAnalyzer::ToMetricName( return out.str(); } +std::string DefaultVideoQualityAnalyzer::GetStreamLabelInternal( + uint16_t frame_id) const { + auto it = captured_frames_in_flight_.find(frame_id); + if (it != captured_frames_in_flight_.end()) { + return streams_.name(it->second.stream()); + } + for (auto hist_it = stream_to_frame_id_history_.begin(); + hist_it != stream_to_frame_id_history_.end(); ++hist_it) { + auto hist_set_it = hist_it->second.find(frame_id); + if (hist_set_it != hist_it->second.end()) { + return streams_.name(hist_it->first); + } + } + RTC_CHECK(false) << "Unknown frame_id=" << frame_id; +} + double DefaultVideoQualityAnalyzer::GetCpuUsagePercent() { return cpu_measurer_.GetCpuUsagePercent(); } diff --git a/test/pc/e2e/analyzer/video/default_video_quality_analyzer.h b/test/pc/e2e/analyzer/video/default_video_quality_analyzer.h index 879fc02347..060a836ccf 100644 --- a/test/pc/e2e/analyzer/video/default_video_quality_analyzer.h +++ b/test/pc/e2e/analyzer/video/default_video_quality_analyzer.h @@ -89,6 +89,7 @@ class DefaultVideoQualityAnalyzer : public VideoQualityAnalyzerInterface { void Stop() override; std::string GetStreamLabel(uint16_t frame_id) override; + std::string GetSenderPeerName(uint16_t frame_id) const override; void OnStatsReports( absl::string_view pc_label, const rtc::scoped_refptr& report) override {} @@ -150,6 +151,8 @@ class DefaultVideoQualityAnalyzer : public VideoQualityAnalyzerInterface { // backward compatibility by metrics naming for 2 peers cases. std::string ToMetricName(const InternalStatsKey& key) const RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + std::string GetStreamLabelInternal(uint16_t frame_id) const + RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_); static const uint16_t kStartingFrameId = 1; diff --git a/test/pc/e2e/analyzer/video/default_video_quality_analyzer_test.cc b/test/pc/e2e/analyzer/video/default_video_quality_analyzer_test.cc index 86144a07dd..7b52bad0a8 100644 --- a/test/pc/e2e/analyzer/video/default_video_quality_analyzer_test.cc +++ b/test/pc/e2e/analyzer/video/default_video_quality_analyzer_test.cc @@ -2375,5 +2375,38 @@ TEST_F(DefaultVideoQualityAnalyzerSimulatedTimeTest, EXPECT_EQ(frame_counters.dropped, 0); } +TEST(DefaultVideoQualityAnalyzerTest, CheckFrameSenderPeerName) { + constexpr char kAlice[] = "alice"; + constexpr char kBob[] = "bob"; + constexpr char kAliceStreamLabel[] = "alice-video"; + constexpr char kBobStreamLabel[] = "bob-video"; + std::unique_ptr frame_generator = + test::CreateSquareFrameGenerator(kFrameWidth, kFrameHeight, + /*type=*/absl::nullopt, + /*num_squares=*/absl::nullopt); + DefaultVideoQualityAnalyzer analyzer(Clock::GetRealTimeClock(), + test::GetGlobalMetricsLogger(), + AnalyzerOptionsForTest()); + analyzer.Start("test_case", std::vector{kAlice, kBob}, + kAnalyzerMaxThreadsCount); + + VideoFrame frame_alice = NextFrame(frame_generator.get(), /*timestamp_us=*/1); + VideoFrame frame_bob = NextFrame(frame_generator.get(), /*timestamp_us=*/2); + frame_alice.set_id( + analyzer.OnFrameCaptured(kAlice, kAliceStreamLabel, frame_alice)); + frame_bob.set_id(analyzer.OnFrameCaptured(kBob, kBobStreamLabel, frame_bob)); + std::string sender_alice = analyzer.GetSenderPeerName(frame_alice.id()); + std::string sender_bob = analyzer.GetSenderPeerName(frame_bob.id()); + + // Give analyzer some time to process frames on async thread. The computations + // have to be fast (heavy metrics are disabled!), so if doesn't fit 100ms it + // means we have an issue! + SleepMs(100); + analyzer.Stop(); + + EXPECT_EQ(sender_alice, kAlice); + EXPECT_EQ(sender_bob, kBob); +} + } // namespace } // namespace webrtc diff --git a/test/pc/e2e/analyzer/video/example_video_quality_analyzer.cc b/test/pc/e2e/analyzer/video/example_video_quality_analyzer.cc index da9c53beb9..1d8ec30874 100644 --- a/test/pc/e2e/analyzer/video/example_video_quality_analyzer.cc +++ b/test/pc/e2e/analyzer/video/example_video_quality_analyzer.cc @@ -32,6 +32,7 @@ uint16_t ExampleVideoQualityAnalyzer::OnFrameCaptured( if (frame_id == VideoFrame::kNotSetId) { frame_id = next_frame_id_++; } + stream_label_to_peer_name_[stream_label] = std::string(peer_name); auto it = frames_in_flight_.find(frame_id); if (it == frames_in_flight_.end()) { frames_in_flight_.insert(frame_id); @@ -130,6 +131,15 @@ std::string ExampleVideoQualityAnalyzer::GetStreamLabel(uint16_t frame_id) { return it->second; } +std::string ExampleVideoQualityAnalyzer::GetSenderPeerName( + uint16_t frame_id) const { + MutexLock lock(&lock_); + auto it = frames_to_stream_label_.find(frame_id); + RTC_DCHECK(it != frames_to_stream_label_.end()) + << "Unknown frame_id=" << frame_id; + return stream_label_to_peer_name_.at(it->second); +} + uint64_t ExampleVideoQualityAnalyzer::frames_captured() const { MutexLock lock(&lock_); return frames_captured_; diff --git a/test/pc/e2e/analyzer/video/example_video_quality_analyzer.h b/test/pc/e2e/analyzer/video/example_video_quality_analyzer.h index af4868a961..56cefa5ab6 100644 --- a/test/pc/e2e/analyzer/video/example_video_quality_analyzer.h +++ b/test/pc/e2e/analyzer/video/example_video_quality_analyzer.h @@ -65,6 +65,7 @@ class ExampleVideoQualityAnalyzer : public VideoQualityAnalyzerInterface { const DecoderStats& stats) override; void Stop() override; std::string GetStreamLabel(uint16_t frame_id) override; + std::string GetSenderPeerName(uint16_t frame_id) const override; uint64_t frames_captured() const; uint64_t frames_pre_encoded() const; @@ -86,6 +87,8 @@ class ExampleVideoQualityAnalyzer : public VideoQualityAnalyzerInterface { // process frame id overlap. std::set frames_in_flight_ RTC_GUARDED_BY(lock_); std::map frames_to_stream_label_ RTC_GUARDED_BY(lock_); + std::map stream_label_to_peer_name_ + RTC_GUARDED_BY(lock_); uint16_t next_frame_id_ RTC_GUARDED_BY(lock_) = 1; uint64_t frames_captured_ RTC_GUARDED_BY(lock_) = 0; uint64_t frames_pre_encoded_ RTC_GUARDED_BY(lock_) = 0;