diff --git a/webrtc/common_types.h b/webrtc/common_types.h index 16174dcf75..191d9aa6e0 100644 --- a/webrtc/common_types.h +++ b/webrtc/common_types.h @@ -11,6 +11,7 @@ #ifndef WEBRTC_COMMON_TYPES_H_ #define WEBRTC_COMMON_TYPES_H_ +#include #include #include @@ -791,6 +792,17 @@ struct RtpPacketCounter { packets += other.packets; } + void Subtract(const RtpPacketCounter& other) { + assert(header_bytes >= other.header_bytes); + header_bytes -= other.header_bytes; + assert(payload_bytes >= other.payload_bytes); + payload_bytes -= other.payload_bytes; + assert(padding_bytes >= other.padding_bytes); + padding_bytes -= other.padding_bytes; + assert(packets >= other.packets); + packets -= other.packets; + } + void AddPacket(size_t packet_length, const RTPHeader& header) { ++packets; header_bytes += header.headerLength; @@ -825,6 +837,18 @@ struct StreamDataCounters { } } + void Subtract(const StreamDataCounters& other) { + transmitted.Subtract(other.transmitted); + retransmitted.Subtract(other.retransmitted); + fec.Subtract(other.fec); + if (other.first_packet_time_ms != -1 && + (other.first_packet_time_ms > first_packet_time_ms || + first_packet_time_ms == -1)) { + // Use youngest time. + first_packet_time_ms = other.first_packet_time_ms; + } + } + int64_t TimeSinceFirstPacketInMs(int64_t now_ms) const { return (first_packet_time_ms == -1) ? -1 : (now_ms - first_packet_time_ms); } diff --git a/webrtc/video/end_to_end_tests.cc b/webrtc/video/end_to_end_tests.cc index 94a87d8864..2a88e28836 100644 --- a/webrtc/video/end_to_end_tests.cc +++ b/webrtc/video/end_to_end_tests.cc @@ -2246,20 +2246,19 @@ void EndToEndTest::VerifyHistogramStats(bool use_rtx, EXPECT_EQ(1, test::NumHistogramSamples(video_prefix + "EncodeTimeInMs")); EXPECT_EQ(1, test::NumHistogramSamples("WebRTC.Video.DecodeTimeInMs")); - EXPECT_EQ(1, test::NumHistogramSamples( - "WebRTC.Video.BitrateSentInKbps")); + EXPECT_EQ(1, test::NumHistogramSamples(video_prefix + "BitrateSentInKbps")); EXPECT_EQ(1, test::NumHistogramSamples( "WebRTC.Video.BitrateReceivedInKbps")); - EXPECT_EQ(1, test::NumHistogramSamples( - "WebRTC.Video.MediaBitrateSentInKbps")); + EXPECT_EQ(1, + test::NumHistogramSamples(video_prefix + "MediaBitrateSentInKbps")); EXPECT_EQ(1, test::NumHistogramSamples( "WebRTC.Video.MediaBitrateReceivedInKbps")); - EXPECT_EQ(1, test::NumHistogramSamples( - "WebRTC.Video.PaddingBitrateSentInKbps")); + EXPECT_EQ( + 1, test::NumHistogramSamples(video_prefix + "PaddingBitrateSentInKbps")); EXPECT_EQ(1, test::NumHistogramSamples( "WebRTC.Video.PaddingBitrateReceivedInKbps")); - EXPECT_EQ(1, test::NumHistogramSamples( - "WebRTC.Video.RetransmittedBitrateSentInKbps")); + EXPECT_EQ(1, test::NumHistogramSamples(video_prefix + + "RetransmittedBitrateSentInKbps")); EXPECT_EQ(1, test::NumHistogramSamples( "WebRTC.Video.RetransmittedBitrateReceivedInKbps")); diff --git a/webrtc/video/send_statistics_proxy.cc b/webrtc/video/send_statistics_proxy.cc index 729c77535d..6407cdc62e 100644 --- a/webrtc/video/send_statistics_proxy.cc +++ b/webrtc/video/send_statistics_proxy.cc @@ -98,10 +98,26 @@ SendStatisticsProxy::UmaSamplesContainer::UmaSamplesContainer( input_frame_rate_tracker_(100u, 10u), sent_frame_rate_tracker_(100u, 10u), first_rtcp_stats_time_ms_(-1), + first_rtp_stats_time_ms_(-1), start_stats_(stats) {} SendStatisticsProxy::UmaSamplesContainer::~UmaSamplesContainer() {} +void AccumulateRtpStats(const VideoSendStream::Stats& stats, + const VideoSendStream::Config& config, + StreamDataCounters* total_rtp_stats, + StreamDataCounters* rtx_stats) { + for (auto it : stats.substreams) { + const std::vector rtx_ssrcs = config.rtp.rtx.ssrcs; + if (std::find(rtx_ssrcs.begin(), rtx_ssrcs.end(), it.first) != + rtx_ssrcs.end()) { + rtx_stats->Add(it.second.rtp_stats); + } else { + total_rtp_stats->Add(it.second.rtp_stats); + } + } +} + void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms( const VideoSendStream::Config& config, const VideoSendStream::Stats& current_stats) { @@ -223,6 +239,51 @@ void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms( } } } + + if (first_rtp_stats_time_ms_ != -1) { + int64_t elapsed_sec = + (clock_->TimeInMilliseconds() - first_rtp_stats_time_ms_) / 1000; + if (elapsed_sec >= metrics::kMinRunTimeInSeconds) { + StreamDataCounters rtp; + StreamDataCounters rtx; + AccumulateRtpStats(current_stats, config, &rtp, &rtx); + StreamDataCounters start_rtp; + StreamDataCounters start_rtx; + AccumulateRtpStats(start_stats_, config, &start_rtp, &start_rtx); + rtp.Subtract(start_rtp); + rtx.Subtract(start_rtx); + StreamDataCounters rtp_rtx = rtp; + rtp_rtx.Add(rtx); + + RTC_HISTOGRAMS_COUNTS_10000( + kIndex, uma_prefix_ + "BitrateSentInKbps", + static_cast(rtp_rtx.transmitted.TotalBytes() * 8 / elapsed_sec / + 1000)); + RTC_HISTOGRAMS_COUNTS_10000( + kIndex, uma_prefix_ + "MediaBitrateSentInKbps", + static_cast(rtp.MediaPayloadBytes() * 8 / elapsed_sec / 1000)); + RTC_HISTOGRAMS_COUNTS_10000( + kIndex, uma_prefix_ + "PaddingBitrateSentInKbps", + static_cast(rtp_rtx.transmitted.padding_bytes * 8 / elapsed_sec / + 1000)); + RTC_HISTOGRAMS_COUNTS_10000( + kIndex, uma_prefix_ + "RetransmittedBitrateSentInKbps", + static_cast(rtp_rtx.retransmitted.TotalBytes() * 8 / + elapsed_sec / 1000)); + if (!config.rtp.rtx.ssrcs.empty()) { + RTC_HISTOGRAMS_COUNTS_10000( + kIndex, uma_prefix_ + "RtxBitrateSentInKbps", + static_cast(rtx.transmitted.TotalBytes() * 8 / elapsed_sec / + 1000)); + } + if (config.rtp.fec.red_payload_type != -1) { + RTC_HISTOGRAMS_COUNTS_10000(kIndex, + uma_prefix_ + "FecBitrateSentInKbps", + static_cast(rtp_rtx.fec.TotalBytes() * + 8 / elapsed_sec / 1000)); + } + } + } } void SendStatisticsProxy::SetContentType( @@ -429,6 +490,8 @@ void SendStatisticsProxy::DataCountersUpdated( << "DataCountersUpdated reported for unknown ssrc: " << ssrc; stats->rtp_stats = counters; + if (uma_container_->first_rtp_stats_time_ms_ == -1) + uma_container_->first_rtp_stats_time_ms_ = clock_->TimeInMilliseconds(); } void SendStatisticsProxy::Notify(const BitrateStatistics& total_stats, diff --git a/webrtc/video/send_statistics_proxy.h b/webrtc/video/send_statistics_proxy.h index 0d0d0e071a..24a09b0006 100644 --- a/webrtc/video/send_statistics_proxy.h +++ b/webrtc/video/send_statistics_proxy.h @@ -169,6 +169,7 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver, rtc::RateTracker input_frame_rate_tracker_; rtc::RateTracker sent_frame_rate_tracker_; int64_t first_rtcp_stats_time_ms_; + int64_t first_rtp_stats_time_ms_; ReportBlockStats report_block_stats_; const VideoSendStream::Stats start_stats_; }; diff --git a/webrtc/video/send_statistics_proxy_unittest.cc b/webrtc/video/send_statistics_proxy_unittest.cc index c1120132da..b3da5e978a 100644 --- a/webrtc/video/send_statistics_proxy_unittest.cc +++ b/webrtc/video/send_statistics_proxy_unittest.cc @@ -47,6 +47,7 @@ class SendStatisticsProxyTest : public ::testing::Test { config.rtp.ssrcs.push_back(kSecondSsrc); config.rtp.rtx.ssrcs.push_back(kFirstRtxSsrc); config.rtp.rtx.ssrcs.push_back(kSecondRtxSsrc); + config.rtp.fec.red_payload_type = 17; return config; } @@ -525,4 +526,136 @@ TEST_F(SendStatisticsProxyTest, ResetsRtcpCountersOnContentChange) { "WebRTC.Video.Screenshare.UniqueNackRequestsReceivedInPercent")); } +TEST_F(SendStatisticsProxyTest, ResetsRtpCountersOnContentChange) { + StreamDataCountersCallback* proxy = + static_cast(statistics_proxy_.get()); + StreamDataCounters counters; + StreamDataCounters rtx_counters; + counters.first_packet_time_ms = fake_clock_.TimeInMilliseconds(); + proxy->DataCountersUpdated(counters, kFirstSsrc); + proxy->DataCountersUpdated(counters, kSecondSsrc); + proxy->DataCountersUpdated(rtx_counters, kFirstRtxSsrc); + proxy->DataCountersUpdated(rtx_counters, kSecondRtxSsrc); + + counters.transmitted.header_bytes = 400; + counters.transmitted.packets = 20; + counters.transmitted.padding_bytes = 1000; + counters.transmitted.payload_bytes = 2000; + + counters.retransmitted.header_bytes = 40; + counters.retransmitted.packets = 2; + counters.retransmitted.padding_bytes = 100; + counters.retransmitted.payload_bytes = 200; + + counters.fec = counters.retransmitted; + + rtx_counters.transmitted = counters.transmitted; + + fake_clock_.AdvanceTimeMilliseconds(1000 * metrics::kMinRunTimeInSeconds); + proxy->DataCountersUpdated(counters, kFirstSsrc); + proxy->DataCountersUpdated(counters, kSecondSsrc); + proxy->DataCountersUpdated(rtx_counters, kFirstRtxSsrc); + proxy->DataCountersUpdated(rtx_counters, kSecondRtxSsrc); + + // Changing content type causes histograms to be reported. + statistics_proxy_->SetContentType(VideoEncoderConfig::ContentType::kScreen); + + EXPECT_EQ(1, test::NumHistogramSamples("WebRTC.Video.BitrateSentInKbps")); + EXPECT_EQ(static_cast((counters.transmitted.TotalBytes() * 4 * 8) / + metrics::kMinRunTimeInSeconds / 1000), + test::LastHistogramSample("WebRTC.Video.BitrateSentInKbps")); + + EXPECT_EQ(1, + test::NumHistogramSamples("WebRTC.Video.MediaBitrateSentInKbps")); + EXPECT_EQ(static_cast((counters.MediaPayloadBytes() * 2 * 8) / + metrics::kMinRunTimeInSeconds / 1000), + test::LastHistogramSample("WebRTC.Video.MediaBitrateSentInKbps")); + + EXPECT_EQ(1, + test::NumHistogramSamples("WebRTC.Video.PaddingBitrateSentInKbps")); + EXPECT_EQ(static_cast((counters.transmitted.padding_bytes * 4 * 8) / + metrics::kMinRunTimeInSeconds / 1000), + test::LastHistogramSample("WebRTC.Video.PaddingBitrateSentInKbps")); + + EXPECT_EQ(1, test::NumHistogramSamples( + "WebRTC.Video.RetransmittedBitrateSentInKbps")); + EXPECT_EQ( + static_cast((counters.retransmitted.TotalBytes() * 2 * 8) / + metrics::kMinRunTimeInSeconds / 1000), + test::LastHistogramSample("WebRTC.Video.RetransmittedBitrateSentInKbps")); + + EXPECT_EQ(1, test::NumHistogramSamples("WebRTC.Video.RtxBitrateSentInKbps")); + EXPECT_EQ(static_cast((rtx_counters.transmitted.TotalBytes() * 2 * 8) / + metrics::kMinRunTimeInSeconds / 1000), + test::LastHistogramSample("WebRTC.Video.RtxBitrateSentInKbps")); + + EXPECT_EQ(1, test::NumHistogramSamples("WebRTC.Video.FecBitrateSentInKbps")); + EXPECT_EQ(static_cast((rtx_counters.fec.TotalBytes() * 2 * 8) / + metrics::kMinRunTimeInSeconds / 1000), + test::LastHistogramSample("WebRTC.Video.FecBitrateSentInKbps")); + + // New start time but same counter values. + proxy->DataCountersUpdated(counters, kFirstSsrc); + proxy->DataCountersUpdated(counters, kSecondSsrc); + proxy->DataCountersUpdated(rtx_counters, kFirstRtxSsrc); + proxy->DataCountersUpdated(rtx_counters, kSecondRtxSsrc); + + // Double counter values, this should result in the same counts as before but + // with new histogram names. + StreamDataCounters new_counters = counters; + new_counters.Add(counters); + StreamDataCounters new_rtx_counters = rtx_counters; + new_rtx_counters.Add(rtx_counters); + + fake_clock_.AdvanceTimeMilliseconds(1000 * metrics::kMinRunTimeInSeconds); + proxy->DataCountersUpdated(new_counters, kFirstSsrc); + proxy->DataCountersUpdated(new_counters, kSecondSsrc); + proxy->DataCountersUpdated(new_rtx_counters, kFirstRtxSsrc); + proxy->DataCountersUpdated(new_rtx_counters, kSecondRtxSsrc); + + SetUp(); // Reset stats proxy also causes histograms to be reported. + + EXPECT_EQ(1, test::NumHistogramSamples( + "WebRTC.Video.Screenshare.BitrateSentInKbps")); + EXPECT_EQ( + static_cast((counters.transmitted.TotalBytes() * 4 * 8) / + metrics::kMinRunTimeInSeconds / 1000), + test::LastHistogramSample("WebRTC.Video.Screenshare.BitrateSentInKbps")); + + EXPECT_EQ(1, test::NumHistogramSamples( + "WebRTC.Video.Screenshare.MediaBitrateSentInKbps")); + EXPECT_EQ(static_cast((counters.MediaPayloadBytes() * 2 * 8) / + metrics::kMinRunTimeInSeconds / 1000), + test::LastHistogramSample( + "WebRTC.Video.Screenshare.MediaBitrateSentInKbps")); + + EXPECT_EQ(1, test::NumHistogramSamples( + "WebRTC.Video.Screenshare.PaddingBitrateSentInKbps")); + EXPECT_EQ(static_cast((counters.transmitted.padding_bytes * 4 * 8) / + metrics::kMinRunTimeInSeconds / 1000), + test::LastHistogramSample( + "WebRTC.Video.Screenshare.PaddingBitrateSentInKbps")); + + EXPECT_EQ(1, test::NumHistogramSamples( + "WebRTC.Video.Screenshare.RetransmittedBitrateSentInKbps")); + EXPECT_EQ(static_cast((counters.retransmitted.TotalBytes() * 2 * 8) / + metrics::kMinRunTimeInSeconds / 1000), + test::LastHistogramSample( + "WebRTC.Video.Screenshare.RetransmittedBitrateSentInKbps")); + + EXPECT_EQ(1, test::NumHistogramSamples( + "WebRTC.Video.Screenshare.RtxBitrateSentInKbps")); + EXPECT_EQ(static_cast((rtx_counters.transmitted.TotalBytes() * 2 * 8) / + metrics::kMinRunTimeInSeconds / 1000), + test::LastHistogramSample( + "WebRTC.Video.Screenshare.RtxBitrateSentInKbps")); + + EXPECT_EQ(1, test::NumHistogramSamples( + "WebRTC.Video.Screenshare.FecBitrateSentInKbps")); + EXPECT_EQ(static_cast((rtx_counters.fec.TotalBytes() * 2 * 8) / + metrics::kMinRunTimeInSeconds / 1000), + test::LastHistogramSample( + "WebRTC.Video.Screenshare.FecBitrateSentInKbps")); +} + } // namespace webrtc diff --git a/webrtc/video/vie_channel.cc b/webrtc/video/vie_channel.cc index 30992868d1..2b601edb69 100644 --- a/webrtc/video/vie_channel.cc +++ b/webrtc/video/vie_channel.cc @@ -163,7 +163,6 @@ int32_t ViEChannel::Init() { } ViEChannel::~ViEChannel() { - UpdateHistograms(); // Make sure we don't get more callbacks from the RTP module. module_process_thread_->DeRegisterModule( vie_receiver_.GetReceiveStatistics()); @@ -177,52 +176,6 @@ ViEChannel::~ViEChannel() { } } -void ViEChannel::UpdateHistograms() { - if (sender_) { - StreamDataCounters rtp; - StreamDataCounters rtx; - GetSendStreamDataCounters(&rtp, &rtx); - StreamDataCounters rtp_rtx = rtp; - rtp_rtx.Add(rtx); - int64_t elapsed_sec = rtp_rtx.TimeSinceFirstPacketInMs( - Clock::GetRealTimeClock()->TimeInMilliseconds()) / - 1000; - if (elapsed_sec > metrics::kMinRunTimeInSeconds) { - RTC_HISTOGRAM_COUNTS_100000( - "WebRTC.Video.BitrateSentInKbps", - static_cast(rtp_rtx.transmitted.TotalBytes() * 8 / elapsed_sec / - 1000)); - RTC_HISTOGRAM_COUNTS_10000( - "WebRTC.Video.MediaBitrateSentInKbps", - static_cast(rtp.MediaPayloadBytes() * 8 / elapsed_sec / 1000)); - RTC_HISTOGRAM_COUNTS_10000( - "WebRTC.Video.PaddingBitrateSentInKbps", - static_cast(rtp_rtx.transmitted.padding_bytes * 8 / elapsed_sec / - 1000)); - RTC_HISTOGRAM_COUNTS_10000( - "WebRTC.Video.RetransmittedBitrateSentInKbps", - static_cast(rtp_rtx.retransmitted.TotalBytes() * 8 / - elapsed_sec / 1000)); - if (rtp_rtcp_modules_[0]->RtxSendStatus() != kRtxOff) { - RTC_HISTOGRAM_COUNTS_10000( - "WebRTC.Video.RtxBitrateSentInKbps", - static_cast(rtx.transmitted.TotalBytes() * 8 / elapsed_sec / - 1000)); - } - bool fec_enabled = false; - uint8_t pltype_red; - uint8_t pltype_fec; - rtp_rtcp_modules_[0]->GenericFECStatus(&fec_enabled, &pltype_red, - &pltype_fec); - if (fec_enabled) { - RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.FecBitrateSentInKbps", - static_cast(rtp_rtx.fec.TotalBytes() * - 8 / elapsed_sec / 1000)); - } - } - } -} - int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec, bool new_stream) { RTC_DCHECK(sender_); diff --git a/webrtc/video/vie_channel.h b/webrtc/video/vie_channel.h index 2cb623cffa..afb8d890a8 100644 --- a/webrtc/video/vie_channel.h +++ b/webrtc/video/vie_channel.h @@ -200,8 +200,6 @@ class ViEChannel : public VCMFrameTypeCallback, // Compute NACK list parameters for the buffering mode. int GetRequiredNackListSize(int target_delay_ms); - void UpdateHistograms(); - // ViEChannel exposes methods that allow to modify observers and callbacks // to be modified. Such an API-style is cumbersome to implement and maintain // at all the levels when comparing to only setting them at construction. As