From c81afe365d40d3a7392890c8e109f899666bedc2 Mon Sep 17 00:00:00 2001 From: Markus Handell Date: Mon, 31 May 2021 09:02:01 +0200 Subject: [PATCH] Call: prepare receive stats for thread switch. This change collects the receive stats that Call maintains into a new thread-compatible internal class which can easily be switched to the network thread. Bug: webrtc:11993 Change-Id: I9fa9a7f057149789aa327e5ba8a8cb3379762272 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/220760 Reviewed-by: Tommi Commit-Queue: Markus Handell Cr-Commit-Position: refs/heads/master@{#34158} --- call/call.cc | 211 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 128 insertions(+), 83 deletions(-) diff --git a/call/call.cc b/call/call.cc index f543debb5d..cdc57becbc 100644 --- a/call/call.cc +++ b/call/call.cc @@ -321,6 +321,37 @@ class Call final : public webrtc::Call, void SetClientBitratePreferences(const BitrateSettings& preferences) override; private: + // Thread-compatible class that collects received packet stats and exposes + // them as UMA histograms on destruction. + class ReceiveStats { + public: + explicit ReceiveStats(Clock* clock); + ~ReceiveStats(); + + void AddReceivedRtcpBytes(int bytes); + void AddReceivedAudioBytes(int bytes, webrtc::Timestamp arrival_time); + void AddReceivedVideoBytes(int bytes, webrtc::Timestamp arrival_time); + + private: + SequenceChecker sequence_checker_; + RateCounter received_bytes_per_second_counter_ + RTC_GUARDED_BY(sequence_checker_); + RateCounter received_audio_bytes_per_second_counter_ + RTC_GUARDED_BY(sequence_checker_); + RateCounter received_video_bytes_per_second_counter_ + RTC_GUARDED_BY(sequence_checker_); + RateCounter received_rtcp_bytes_per_second_counter_ + RTC_GUARDED_BY(sequence_checker_); + absl::optional first_received_rtp_audio_timestamp_ + RTC_GUARDED_BY(sequence_checker_); + absl::optional last_received_rtp_audio_timestamp_ + RTC_GUARDED_BY(sequence_checker_); + absl::optional first_received_rtp_video_timestamp_ + RTC_GUARDED_BY(sequence_checker_); + absl::optional last_received_rtp_video_timestamp_ + RTC_GUARDED_BY(sequence_checker_); + }; + DeliveryStatus DeliverRtcp(MediaType media_type, const uint8_t* packet, size_t length) @@ -336,7 +367,6 @@ class Call final : public webrtc::Call, MediaType media_type) RTC_SHARED_LOCKS_REQUIRED(worker_thread_); - void UpdateReceiveHistograms(); void UpdateAggregateNetworkState(); // Ensure that necessary process threads are started, and any required @@ -433,17 +463,9 @@ class Call final : public webrtc::Call, webrtc::RtcEventLog* event_log_; - // The following members are only accessed (exclusively) from one thread and - // from the destructor, and therefore doesn't need any explicit - // synchronization. - RateCounter received_bytes_per_second_counter_; - RateCounter received_audio_bytes_per_second_counter_; - RateCounter received_video_bytes_per_second_counter_; - RateCounter received_rtcp_bytes_per_second_counter_; - absl::optional first_received_rtp_audio_ms_; - absl::optional last_received_rtp_audio_ms_; - absl::optional first_received_rtp_video_ms_; - absl::optional last_received_rtp_video_ms_; + // TODO(bugs.webrtc.org/11993) ready to move receive stats access to the + // network thread. + ReceiveStats receive_stats_ RTC_GUARDED_BY(worker_thread_); uint32_t last_bandwidth_bps_ RTC_GUARDED_BY(worker_thread_); // TODO(holmer): Remove this lock once BitrateController no longer calls @@ -625,6 +647,94 @@ VideoSendStream* Call::CreateVideoSendStream( namespace internal { +Call::ReceiveStats::ReceiveStats(Clock* clock) + : received_bytes_per_second_counter_(clock, nullptr, false), + received_audio_bytes_per_second_counter_(clock, nullptr, false), + received_video_bytes_per_second_counter_(clock, nullptr, false), + received_rtcp_bytes_per_second_counter_(clock, nullptr, false) { + sequence_checker_.Detach(); +} + +void Call::ReceiveStats::AddReceivedRtcpBytes(int bytes) { + RTC_DCHECK_RUN_ON(&sequence_checker_); + if (received_bytes_per_second_counter_.HasSample()) { + // First RTP packet has been received. + received_bytes_per_second_counter_.Add(static_cast(bytes)); + received_rtcp_bytes_per_second_counter_.Add(static_cast(bytes)); + } +} + +void Call::ReceiveStats::AddReceivedAudioBytes(int bytes, + webrtc::Timestamp arrival_time) { + RTC_DCHECK_RUN_ON(&sequence_checker_); + received_bytes_per_second_counter_.Add(bytes); + received_audio_bytes_per_second_counter_.Add(bytes); + if (!first_received_rtp_audio_timestamp_) + first_received_rtp_audio_timestamp_ = arrival_time; + last_received_rtp_audio_timestamp_ = arrival_time; +} + +void Call::ReceiveStats::AddReceivedVideoBytes(int bytes, + webrtc::Timestamp arrival_time) { + RTC_DCHECK_RUN_ON(&sequence_checker_); + received_bytes_per_second_counter_.Add(bytes); + received_video_bytes_per_second_counter_.Add(bytes); + if (!first_received_rtp_video_timestamp_) + first_received_rtp_video_timestamp_ = arrival_time; + last_received_rtp_video_timestamp_ = arrival_time; +} + +Call::ReceiveStats::~ReceiveStats() { + RTC_DCHECK_RUN_ON(&sequence_checker_); + if (first_received_rtp_audio_timestamp_) { + RTC_HISTOGRAM_COUNTS_100000( + "WebRTC.Call.TimeReceivingAudioRtpPacketsInSeconds", + (*last_received_rtp_audio_timestamp_ - + *first_received_rtp_audio_timestamp_) + .seconds()); + } + if (first_received_rtp_video_timestamp_) { + RTC_HISTOGRAM_COUNTS_100000( + "WebRTC.Call.TimeReceivingVideoRtpPacketsInSeconds", + (*last_received_rtp_video_timestamp_ - + *first_received_rtp_video_timestamp_) + .seconds()); + } + const int kMinRequiredPeriodicSamples = 5; + AggregatedStats video_bytes_per_sec = + received_video_bytes_per_second_counter_.GetStats(); + if (video_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) { + RTC_HISTOGRAM_COUNTS_100000("WebRTC.Call.VideoBitrateReceivedInKbps", + video_bytes_per_sec.average * 8 / 1000); + RTC_LOG(LS_INFO) << "WebRTC.Call.VideoBitrateReceivedInBps, " + << video_bytes_per_sec.ToStringWithMultiplier(8); + } + AggregatedStats audio_bytes_per_sec = + received_audio_bytes_per_second_counter_.GetStats(); + if (audio_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) { + RTC_HISTOGRAM_COUNTS_100000("WebRTC.Call.AudioBitrateReceivedInKbps", + audio_bytes_per_sec.average * 8 / 1000); + RTC_LOG(LS_INFO) << "WebRTC.Call.AudioBitrateReceivedInBps, " + << audio_bytes_per_sec.ToStringWithMultiplier(8); + } + AggregatedStats rtcp_bytes_per_sec = + received_rtcp_bytes_per_second_counter_.GetStats(); + if (rtcp_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) { + RTC_HISTOGRAM_COUNTS_100000("WebRTC.Call.RtcpBitrateReceivedInBps", + rtcp_bytes_per_sec.average * 8); + RTC_LOG(LS_INFO) << "WebRTC.Call.RtcpBitrateReceivedInBps, " + << rtcp_bytes_per_sec.ToStringWithMultiplier(8); + } + AggregatedStats recv_bytes_per_sec = + received_bytes_per_second_counter_.GetStats(); + if (recv_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) { + RTC_HISTOGRAM_COUNTS_100000("WebRTC.Call.BitrateReceivedInKbps", + recv_bytes_per_sec.average * 8 / 1000); + RTC_LOG(LS_INFO) << "WebRTC.Call.BitrateReceivedInBps, " + << recv_bytes_per_sec.ToStringWithMultiplier(8); + } +} + Call::Call(Clock* clock, const Call::Config& config, std::unique_ptr transport_send, @@ -646,10 +756,7 @@ Call::Call(Clock* clock, video_network_state_(kNetworkDown), aggregate_network_up_(false), event_log_(config.event_log), - received_bytes_per_second_counter_(clock_, nullptr, true), - received_audio_bytes_per_second_counter_(clock_, nullptr, true), - received_video_bytes_per_second_counter_(clock_, nullptr, true), - received_rtcp_bytes_per_second_counter_(clock_, nullptr, true), + receive_stats_(clock_), last_bandwidth_bps_(0), min_allocated_send_bitrate_bps_(0), configured_max_padding_bitrate_bps_(0), @@ -710,8 +817,6 @@ Call::~Call() { pacer_bitrate_kbps_counter_); } - UpdateReceiveHistograms(); - RTC_HISTOGRAM_COUNTS_100000("WebRTC.Call.LifetimeInSeconds", (now.ms() - start_ms_) / 1000); } @@ -737,52 +842,6 @@ void Call::SetClientBitratePreferences(const BitrateSettings& preferences) { GetTransportControllerSend()->SetClientBitratePreferences(preferences); } -void Call::UpdateReceiveHistograms() { - if (first_received_rtp_audio_ms_) { - RTC_HISTOGRAM_COUNTS_100000( - "WebRTC.Call.TimeReceivingAudioRtpPacketsInSeconds", - (*last_received_rtp_audio_ms_ - *first_received_rtp_audio_ms_) / 1000); - } - if (first_received_rtp_video_ms_) { - RTC_HISTOGRAM_COUNTS_100000( - "WebRTC.Call.TimeReceivingVideoRtpPacketsInSeconds", - (*last_received_rtp_video_ms_ - *first_received_rtp_video_ms_) / 1000); - } - const int kMinRequiredPeriodicSamples = 5; - AggregatedStats video_bytes_per_sec = - received_video_bytes_per_second_counter_.GetStats(); - if (video_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) { - RTC_HISTOGRAM_COUNTS_100000("WebRTC.Call.VideoBitrateReceivedInKbps", - video_bytes_per_sec.average * 8 / 1000); - RTC_LOG(LS_INFO) << "WebRTC.Call.VideoBitrateReceivedInBps, " - << video_bytes_per_sec.ToStringWithMultiplier(8); - } - AggregatedStats audio_bytes_per_sec = - received_audio_bytes_per_second_counter_.GetStats(); - if (audio_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) { - RTC_HISTOGRAM_COUNTS_100000("WebRTC.Call.AudioBitrateReceivedInKbps", - audio_bytes_per_sec.average * 8 / 1000); - RTC_LOG(LS_INFO) << "WebRTC.Call.AudioBitrateReceivedInBps, " - << audio_bytes_per_sec.ToStringWithMultiplier(8); - } - AggregatedStats rtcp_bytes_per_sec = - received_rtcp_bytes_per_second_counter_.GetStats(); - if (rtcp_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) { - RTC_HISTOGRAM_COUNTS_100000("WebRTC.Call.RtcpBitrateReceivedInBps", - rtcp_bytes_per_sec.average * 8); - RTC_LOG(LS_INFO) << "WebRTC.Call.RtcpBitrateReceivedInBps, " - << rtcp_bytes_per_sec.ToStringWithMultiplier(8); - } - AggregatedStats recv_bytes_per_sec = - received_bytes_per_second_counter_.GetStats(); - if (recv_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) { - RTC_HISTOGRAM_COUNTS_100000("WebRTC.Call.BitrateReceivedInKbps", - recv_bytes_per_sec.average * 8 / 1000); - RTC_LOG(LS_INFO) << "WebRTC.Call.BitrateReceivedInBps, " - << recv_bytes_per_sec.ToStringWithMultiplier(8); - } -} - PacketReceiver* Call::Receiver() { return this; } @@ -1381,11 +1440,7 @@ PacketReceiver::DeliveryStatus Call::DeliverRtcp(MediaType media_type, // TODO(pbos): Make sure it's a valid packet. // Return DELIVERY_UNKNOWN_SSRC if it can be determined that // there's no receiver of the packet. - if (received_bytes_per_second_counter_.HasSample()) { - // First RTP packet has been received. - received_bytes_per_second_counter_.Add(static_cast(length)); - received_rtcp_bytes_per_second_counter_.Add(static_cast(length)); - } + receive_stats_.AddReceivedRtcpBytes(static_cast(length)); bool rtcp_delivered = false; if (media_type == MediaType::ANY || media_type == MediaType::VIDEO) { for (VideoReceiveStream2* stream : video_receive_streams_) { @@ -1471,29 +1526,19 @@ PacketReceiver::DeliveryStatus Call::DeliverRtp(MediaType media_type, int length = static_cast(parsed_packet.size()); if (media_type == MediaType::AUDIO) { if (audio_receiver_controller_.OnRtpPacket(parsed_packet)) { - received_bytes_per_second_counter_.Add(length); - received_audio_bytes_per_second_counter_.Add(length); + receive_stats_.AddReceivedAudioBytes(length, + parsed_packet.arrival_time()); event_log_->Log( std::make_unique(parsed_packet)); - const int64_t arrival_time_ms = parsed_packet.arrival_time().ms(); - if (!first_received_rtp_audio_ms_) { - first_received_rtp_audio_ms_.emplace(arrival_time_ms); - } - last_received_rtp_audio_ms_.emplace(arrival_time_ms); return DELIVERY_OK; } } else if (media_type == MediaType::VIDEO) { parsed_packet.set_payload_type_frequency(kVideoPayloadTypeFrequency); if (video_receiver_controller_.OnRtpPacket(parsed_packet)) { - received_bytes_per_second_counter_.Add(length); - received_video_bytes_per_second_counter_.Add(length); + receive_stats_.AddReceivedVideoBytes(length, + parsed_packet.arrival_time()); event_log_->Log( std::make_unique(parsed_packet)); - const int64_t arrival_time_ms = parsed_packet.arrival_time().ms(); - if (!first_received_rtp_video_ms_) { - first_received_rtp_video_ms_.emplace(arrival_time_ms); - } - last_received_rtp_video_ms_.emplace(arrival_time_ms); return DELIVERY_OK; } }