diff options
author | Henrik Boström <hbos@webrtc.org> | 2020-05-05 15:54:46 +0200 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-05-05 20:22:19 +0000 |
commit | a0ff50c0318396f65f25a4ea9e7803858aa84ea7 (patch) | |
tree | 3ed2abeb58c1ee0aaf95606e8df0132b964c1656 /media | |
parent | c0df5fc25b82fc5a2071be55e5357ce786caf637 (diff) | |
download | webrtc-a0ff50c0318396f65f25a4ea9e7803858aa84ea7.tar.gz |
Reland "Improve outbound-rtp statistics for simulcast"
This reverts commit 9a925c9ce33a6ccdd11b545b11ba68e985c2a65d.
Reason for revert: The original CL is updated in PS #2 to
fix the googRtt issue which was that when the legacy sender
stats were put in "aggregated_senders" we forgot to update
rtt_ms the same way that we do it for "senders".
Original change's description:
> Revert "Improve outbound-rtp statistics for simulcast"
>
> This reverts commit da6cda839dac7d9d18eba8d365188fa94831e0b1.
>
> Reason for revert: Breaks googRtt in legacy getStats API
>
> Original change's description:
> > Improve outbound-rtp statistics for simulcast
> >
> > Bug: webrtc:9547
> > Change-Id: Iec4eb976aa11ee743805425bedb77dcea7c2c9be
> > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/168120
> > Reviewed-by: Sebastian Jansson <srte@webrtc.org>
> > Reviewed-by: Erik Språng <sprang@webrtc.org>
> > Reviewed-by: Henrik Boström <hbos@webrtc.org>
> > Reviewed-by: Harald Alvestrand <hta@webrtc.org>
> > Commit-Queue: Eldar Rello <elrello@microsoft.com>
> > Cr-Commit-Position: refs/heads/master@{#31097}
>
> TBR=hbos@webrtc.org,sprang@webrtc.org,stefan@webrtc.org,srte@webrtc.org,hta@webrtc.org,elrello@microsoft.com
>
> # Not skipping CQ checks because original CL landed > 1 day ago.
>
> Bug: webrtc:9547
> Change-Id: I06673328c2a5293a7eef03b3aaf2ded9d13df1b3
> Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/174443
> Reviewed-by: Henrik Boström <hbos@webrtc.org>
> Commit-Queue: Henrik Boström <hbos@webrtc.org>
> Cr-Commit-Position: refs/heads/master@{#31165}
TBR=hbos@webrtc.org,sprang@webrtc.org,stefan@webrtc.org,srte@webrtc.org,hta@webrtc.org,elrello@microsoft.com
# Not skipping CQ checks because this is a reland.
Bug: webrtc:9547
Change-Id: I723744c496c3c65f95ab6a8940862c8b9f544338
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/174480
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Commit-Queue: Henrik Boström <hbos@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#31169}
Diffstat (limited to 'media')
-rw-r--r-- | media/base/media_channel.h | 13 | ||||
-rw-r--r-- | media/engine/webrtc_video_engine.cc | 232 | ||||
-rw-r--r-- | media/engine/webrtc_video_engine.h | 7 | ||||
-rw-r--r-- | media/engine/webrtc_video_engine_unittest.cc | 433 |
4 files changed, 570 insertions, 115 deletions
diff --git a/media/base/media_channel.h b/media/base/media_channel.h index 4758cf52ba..d71ec9158a 100644 --- a/media/base/media_channel.h +++ b/media/base/media_channel.h @@ -569,6 +569,7 @@ struct VideoSenderInfo : public MediaSenderInfo { int send_frame_height = 0; int framerate_input = 0; int framerate_sent = 0; + int aggregated_framerate_sent = 0; int nominal_bitrate = 0; int adapt_reason = 0; int adapt_changes = 0; @@ -592,8 +593,11 @@ struct VideoSenderInfo : public MediaSenderInfo { bool has_entered_low_resolution = false; absl::optional<uint64_t> qp_sum; webrtc::VideoContentType content_type = webrtc::VideoContentType::UNSPECIFIED; + uint32_t frames_sent = 0; // https://w3c.github.io/webrtc-stats/#dom-rtcvideosenderstats-hugeframessent uint32_t huge_frames_sent = 0; + uint32_t aggregated_huge_frames_sent = 0; + absl::optional<std::string> rid; }; struct VideoReceiverInfo : public MediaReceiverInfo { @@ -713,11 +717,20 @@ struct VideoMediaInfo { ~VideoMediaInfo(); void Clear() { senders.clear(); + aggregated_senders.clear(); receivers.clear(); send_codecs.clear(); receive_codecs.clear(); } + // Each sender info represents one "outbound-rtp" stream.In non - simulcast, + // this means one info per RtpSender but if simulcast is used this means + // one info per simulcast layer. std::vector<VideoSenderInfo> senders; + // Used for legacy getStats() API's "ssrc" stats and modern getStats() API's + // "track" stats. If simulcast is used, instead of having one sender info per + // simulcast layer, the metrics of all layers of an RtpSender are aggregated + // into a single sender info per RtpSender. + std::vector<VideoSenderInfo> aggregated_senders; std::vector<VideoReceiverInfo> receivers; RtpCodecParametersMap send_codecs; RtpCodecParametersMap receive_codecs; diff --git a/media/engine/webrtc_video_engine.cc b/media/engine/webrtc_video_engine.cc index 092fb672f8..71a0939cb9 100644 --- a/media/engine/webrtc_video_engine.cc +++ b/media/engine/webrtc_video_engine.cc @@ -1570,6 +1570,9 @@ bool WebRtcVideoChannel::GetStats(VideoMediaInfo* info) { for (size_t i = 0; i < info->senders.size(); ++i) { info->senders[i].rtt_ms = stats.rtt_ms; } + for (size_t i = 0; i < info->aggregated_senders.size(); ++i) { + info->aggregated_senders[i].rtt_ms = stats.rtt_ms; + } } if (log_stats) @@ -1583,8 +1586,12 @@ void WebRtcVideoChannel::FillSenderStats(VideoMediaInfo* video_media_info, for (std::map<uint32_t, WebRtcVideoSendStream*>::iterator it = send_streams_.begin(); it != send_streams_.end(); ++it) { - video_media_info->senders.push_back( - it->second->GetVideoSenderInfo(log_stats)); + auto infos = it->second->GetPerLayerVideoSenderInfos(log_stats); + video_media_info->aggregated_senders.push_back( + it->second->GetAggregatedVideoSenderInfo(infos)); + for (auto&& info : infos) { + video_media_info->senders.push_back(info); + } } } @@ -2474,108 +2481,161 @@ void WebRtcVideoChannel::WebRtcVideoSendStream::AddOrUpdateSink( }); } } - -VideoSenderInfo WebRtcVideoChannel::WebRtcVideoSendStream::GetVideoSenderInfo( +std::vector<VideoSenderInfo> +WebRtcVideoChannel::WebRtcVideoSendStream::GetPerLayerVideoSenderInfos( bool log_stats) { - VideoSenderInfo info; RTC_DCHECK_RUN_ON(&thread_checker_); - for (uint32_t ssrc : parameters_.config.rtp.ssrcs) - info.add_ssrc(ssrc); - + VideoSenderInfo common_info; if (parameters_.codec_settings) { - info.codec_name = parameters_.codec_settings->codec.name; - info.codec_payload_type = parameters_.codec_settings->codec.id; + common_info.codec_name = parameters_.codec_settings->codec.name; + common_info.codec_payload_type = parameters_.codec_settings->codec.id; } - - if (stream_ == NULL) - return info; - - webrtc::VideoSendStream::Stats stats = stream_->GetStats(); - - if (log_stats) - RTC_LOG(LS_INFO) << stats.ToString(rtc::TimeMillis()); - - info.adapt_changes = stats.number_of_cpu_adapt_changes; - info.adapt_reason = - stats.cpu_limited_resolution ? ADAPTREASON_CPU : ADAPTREASON_NONE; - info.has_entered_low_resolution = stats.has_entered_low_resolution; - - // Get bandwidth limitation info from stream_->GetStats(). - // Input resolution (output from video_adapter) can be further scaled down or - // higher video layer(s) can be dropped due to bitrate constraints. - // Note, adapt_changes only include changes from the video_adapter. - if (stats.bw_limited_resolution) - info.adapt_reason |= ADAPTREASON_BANDWIDTH; - - info.quality_limitation_reason = stats.quality_limitation_reason; - info.quality_limitation_durations_ms = stats.quality_limitation_durations_ms; - info.quality_limitation_resolution_changes = - stats.quality_limitation_resolution_changes; - info.encoder_implementation_name = stats.encoder_implementation_name; - info.ssrc_groups = ssrc_groups_; - info.framerate_input = stats.input_frame_rate; - info.framerate_sent = stats.encode_frame_rate; - info.avg_encode_ms = stats.avg_encode_time_ms; - info.encode_usage_percent = stats.encode_usage_percent; - info.frames_encoded = stats.frames_encoded; - // TODO(bugs.webrtc.org/9547): Populate individual outbound-rtp stats objects - // for each simulcast stream, instead of accumulating all keyframes encoded - // over all simulcast streams in the same outbound-rtp stats object. - info.key_frames_encoded = 0; - for (const auto& kv : stats.substreams) { - info.key_frames_encoded += kv.second.frame_counts.key_frames; - } - info.total_encode_time_ms = stats.total_encode_time_ms; - info.total_encoded_bytes_target = stats.total_encoded_bytes_target; - info.qp_sum = stats.qp_sum; - - info.nominal_bitrate = stats.media_bitrate_bps; - - info.content_type = stats.content_type; - info.huge_frames_sent = stats.huge_frames_sent; - - info.send_frame_width = 0; - info.send_frame_height = 0; - info.total_packet_send_delay_ms = 0; - std::map<uint32_t, webrtc::VideoSendStream::StreamStats> - outbound_rtp_substreams = - MergeInfoAboutOutboundRtpSubstreams(stats.substreams); + std::vector<VideoSenderInfo> infos; + webrtc::VideoSendStream::Stats stats; + if (stream_ == nullptr) { + for (uint32_t ssrc : parameters_.config.rtp.ssrcs) { + common_info.add_ssrc(ssrc); + } + infos.push_back(common_info); + return infos; + } else { + stats = stream_->GetStats(); + if (log_stats) + RTC_LOG(LS_INFO) << stats.ToString(rtc::TimeMillis()); + + // Metrics that are in common for all substreams. + common_info.adapt_changes = stats.number_of_cpu_adapt_changes; + common_info.adapt_reason = + stats.cpu_limited_resolution ? ADAPTREASON_CPU : ADAPTREASON_NONE; + common_info.has_entered_low_resolution = stats.has_entered_low_resolution; + + // Get bandwidth limitation info from stream_->GetStats(). + // Input resolution (output from video_adapter) can be further scaled down + // or higher video layer(s) can be dropped due to bitrate constraints. + // Note, adapt_changes only include changes from the video_adapter. + if (stats.bw_limited_resolution) + common_info.adapt_reason |= ADAPTREASON_BANDWIDTH; + + common_info.quality_limitation_reason = stats.quality_limitation_reason; + common_info.quality_limitation_durations_ms = + stats.quality_limitation_durations_ms; + common_info.quality_limitation_resolution_changes = + stats.quality_limitation_resolution_changes; + common_info.encoder_implementation_name = stats.encoder_implementation_name; + common_info.ssrc_groups = ssrc_groups_; + common_info.framerate_input = stats.input_frame_rate; + common_info.avg_encode_ms = stats.avg_encode_time_ms; + common_info.encode_usage_percent = stats.encode_usage_percent; + common_info.nominal_bitrate = stats.media_bitrate_bps; + common_info.content_type = stats.content_type; + common_info.aggregated_framerate_sent = stats.encode_frame_rate; + common_info.aggregated_huge_frames_sent = stats.huge_frames_sent; + + // If we don't have any substreams, get the remaining metrics from |stats|. + // Otherwise, these values are obtained from |sub_stream| below. + if (stats.substreams.empty()) { + for (uint32_t ssrc : parameters_.config.rtp.ssrcs) { + common_info.add_ssrc(ssrc); + } + common_info.framerate_sent = stats.encode_frame_rate; + common_info.frames_encoded = stats.frames_encoded; + common_info.total_encode_time_ms = stats.total_encode_time_ms; + common_info.total_encoded_bytes_target = stats.total_encoded_bytes_target; + common_info.frames_sent = stats.frames_encoded; + common_info.huge_frames_sent = stats.huge_frames_sent; + infos.push_back(common_info); + return infos; + } + } + auto outbound_rtp_substreams = + MergeInfoAboutOutboundRtpSubstreams(stats.substreams); for (const auto& pair : outbound_rtp_substreams) { - // TODO(pbos): Wire up additional stats, such as padding bytes. - const webrtc::VideoSendStream::StreamStats& stream_stats = pair.second; + auto info = common_info; + info.add_ssrc(pair.first); + info.rid = parameters_.config.rtp.GetRidForSsrc(pair.first); + auto stream_stats = pair.second; RTC_DCHECK_EQ(stream_stats.type, webrtc::VideoSendStream::StreamStats::StreamType::kMedia); - info.payload_bytes_sent += stream_stats.rtp_stats.transmitted.payload_bytes; - info.header_and_padding_bytes_sent += + info.payload_bytes_sent = stream_stats.rtp_stats.transmitted.payload_bytes; + info.header_and_padding_bytes_sent = stream_stats.rtp_stats.transmitted.header_bytes + stream_stats.rtp_stats.transmitted.padding_bytes; - info.packets_sent += stream_stats.rtp_stats.transmitted.packets; + info.packets_sent = stream_stats.rtp_stats.transmitted.packets; info.total_packet_send_delay_ms += stream_stats.total_packet_send_delay_ms; - info.retransmitted_bytes_sent += + info.send_frame_width = stream_stats.width; + info.send_frame_height = stream_stats.height; + info.key_frames_encoded = stream_stats.frame_counts.key_frames; + info.framerate_sent = stream_stats.encode_frame_rate; + info.frames_encoded = stream_stats.frames_encoded; + info.frames_sent = stream_stats.frames_encoded; + info.retransmitted_bytes_sent = stream_stats.rtp_stats.retransmitted.payload_bytes; - info.retransmitted_packets_sent += + info.retransmitted_packets_sent = stream_stats.rtp_stats.retransmitted.packets; - info.packets_lost += stream_stats.rtcp_stats.packets_lost; - if (stream_stats.width > info.send_frame_width) - info.send_frame_width = stream_stats.width; - if (stream_stats.height > info.send_frame_height) - info.send_frame_height = stream_stats.height; - info.firs_rcvd += stream_stats.rtcp_packet_type_counts.fir_packets; - info.nacks_rcvd += stream_stats.rtcp_packet_type_counts.nack_packets; - info.plis_rcvd += stream_stats.rtcp_packet_type_counts.pli_packets; + info.packets_lost = stream_stats.rtcp_stats.packets_lost; + info.firs_rcvd = stream_stats.rtcp_packet_type_counts.fir_packets; + info.nacks_rcvd = stream_stats.rtcp_packet_type_counts.nack_packets; + info.plis_rcvd = stream_stats.rtcp_packet_type_counts.pli_packets; if (stream_stats.report_block_data.has_value()) { info.report_block_datas.push_back(stream_stats.report_block_data.value()); } - } - if (!stats.substreams.empty()) { - // TODO(pbos): Report fraction lost per SSRC. - webrtc::VideoSendStream::StreamStats first_stream_stats = - stats.substreams.begin()->second; info.fraction_lost = - static_cast<float>(first_stream_stats.rtcp_stats.fraction_lost) / - (1 << 8); + static_cast<float>(stream_stats.rtcp_stats.fraction_lost) / (1 << 8); + info.qp_sum = stream_stats.qp_sum; + info.total_encode_time_ms = stream_stats.total_encode_time_ms; + info.total_encoded_bytes_target = stream_stats.total_encoded_bytes_target; + info.huge_frames_sent = stream_stats.huge_frames_sent; + infos.push_back(info); } + return infos; +} +VideoSenderInfo +WebRtcVideoChannel::WebRtcVideoSendStream::GetAggregatedVideoSenderInfo( + const std::vector<VideoSenderInfo>& infos) const { + RTC_DCHECK_RUN_ON(&thread_checker_); + RTC_DCHECK(!infos.empty()); + if (infos.size() == 1) { + return infos[0]; + } + VideoSenderInfo info = infos[0]; + info.local_stats.clear(); + for (uint32_t ssrc : parameters_.config.rtp.ssrcs) { + info.add_ssrc(ssrc); + } + info.framerate_sent = info.aggregated_framerate_sent; + info.huge_frames_sent = info.aggregated_huge_frames_sent; + + for (size_t i = 1; i < infos.size(); i++) { + info.key_frames_encoded += infos[i].key_frames_encoded; + info.payload_bytes_sent += infos[i].payload_bytes_sent; + info.header_and_padding_bytes_sent += + infos[i].header_and_padding_bytes_sent; + info.packets_sent += infos[i].packets_sent; + info.total_packet_send_delay_ms += infos[i].total_packet_send_delay_ms; + info.retransmitted_bytes_sent += infos[i].retransmitted_bytes_sent; + info.retransmitted_packets_sent += infos[i].retransmitted_packets_sent; + info.packets_lost += infos[i].packets_lost; + if (infos[i].send_frame_width > info.send_frame_width) + info.send_frame_width = infos[i].send_frame_width; + if (infos[i].send_frame_height > info.send_frame_height) + info.send_frame_height = infos[i].send_frame_height; + info.firs_rcvd += infos[i].firs_rcvd; + info.nacks_rcvd += infos[i].nacks_rcvd; + info.plis_rcvd += infos[i].plis_rcvd; + if (infos[i].report_block_datas.size()) + info.report_block_datas.push_back(infos[i].report_block_datas[0]); + if (infos[i].qp_sum) { + if (!info.qp_sum) { + info.qp_sum = 0; + } + info.qp_sum = *info.qp_sum + *infos[i].qp_sum; + } + info.frames_encoded += infos[i].frames_encoded; + info.frames_sent += infos[i].frames_sent; + info.total_encode_time_ms += infos[i].total_encode_time_ms; + info.total_encoded_bytes_target += infos[i].total_encoded_bytes_target; + } return info; } diff --git a/media/engine/webrtc_video_engine.h b/media/engine/webrtc_video_engine.h index 6ed556e359..00d249541a 100644 --- a/media/engine/webrtc_video_engine.h +++ b/media/engine/webrtc_video_engine.h @@ -357,7 +357,12 @@ class WebRtcVideoChannel : public VideoMediaChannel, void SetSend(bool send); const std::vector<uint32_t>& GetSsrcs() const; - VideoSenderInfo GetVideoSenderInfo(bool log_stats); + // Returns per ssrc VideoSenderInfos. Useful for simulcast scenario. + std::vector<VideoSenderInfo> GetPerLayerVideoSenderInfos(bool log_stats); + // Aggregates per ssrc VideoSenderInfos to single VideoSenderInfo for + // legacy reasons. Used in old GetStats API and track stats. + VideoSenderInfo GetAggregatedVideoSenderInfo( + const std::vector<VideoSenderInfo>& infos) const; void FillBitrateInfo(BandwidthEstimationInfo* bwe_info); void SetEncoderToPacketizerFrameTransformer( diff --git a/media/engine/webrtc_video_engine_unittest.cc b/media/engine/webrtc_video_engine_unittest.cc index 27206db199..4a33c5152b 100644 --- a/media/engine/webrtc_video_engine_unittest.cc +++ b/media/engine/webrtc_video_engine_unittest.cc @@ -2425,6 +2425,18 @@ class WebRtcVideoChannelTest : public WebRtcVideoEngineTest { ASSERT_TRUE(channel_->SetSendParameters(send_parameters_)); } + cricket::VideoCodec GetEngineCodec(const std::string& name) { + for (const cricket::VideoCodec& engine_codec : engine_.send_codecs()) { + if (absl::EqualsIgnoreCase(name, engine_codec.name)) + return engine_codec; + } + // This point should never be reached. + ADD_FAILURE() << "Unrecognized codec name: " << name; + return cricket::VideoCodec(); + } + + cricket::VideoCodec DefaultCodec() { return GetEngineCodec("VP8"); } + protected: FakeVideoSendStream* AddSendStream() { return AddSendStream(StreamParams::CreateLegacy(++last_ssrc_)); @@ -5218,21 +5230,369 @@ TEST_F(WebRtcVideoChannelTest, GetStatsReportsKeyFramesEncoded) { cricket::VideoMediaInfo info; ASSERT_TRUE(channel_->GetStats(&info)); - // TODO(bugs.webrtc.org/9547): Populate individual outbound-rtp stats objects - // for each simulcast stream, instead of accumulating all keyframes encoded - // over all simulcast streams in the same outbound-rtp stats object. - EXPECT_EQ(97u, info.senders[0].key_frames_encoded); + EXPECT_EQ(info.senders.size(), 2u); + EXPECT_EQ(10u, info.senders[0].key_frames_encoded); + EXPECT_EQ(87u, info.senders[1].key_frames_encoded); + EXPECT_EQ(97u, info.aggregated_senders[0].key_frames_encoded); } -TEST_F(WebRtcVideoChannelTest, GetStatsReportsQpSum) { +TEST_F(WebRtcVideoChannelTest, GetStatsReportsPerLayerQpSum) { FakeVideoSendStream* stream = AddSendStream(); webrtc::VideoSendStream::Stats stats; - stats.qp_sum = 13; + stats.substreams[123].qp_sum = 15; + stats.substreams[456].qp_sum = 11; stream->SetStats(stats); cricket::VideoMediaInfo info; ASSERT_TRUE(channel_->GetStats(&info)); - EXPECT_EQ(stats.qp_sum, info.senders[0].qp_sum); + EXPECT_EQ(info.senders.size(), 2u); + EXPECT_EQ(stats.substreams[123].qp_sum, info.senders[0].qp_sum); + EXPECT_EQ(stats.substreams[456].qp_sum, info.senders[1].qp_sum); + EXPECT_EQ(*info.aggregated_senders[0].qp_sum, 26u); +} + +webrtc::VideoSendStream::Stats GetInitialisedStats() { + webrtc::VideoSendStream::Stats stats; + stats.encoder_implementation_name = "vp"; + stats.input_frame_rate = 1; + stats.encode_frame_rate = 2; + stats.avg_encode_time_ms = 3; + stats.encode_usage_percent = 4; + stats.frames_encoded = 5; + stats.total_encode_time_ms = 6; + stats.frames_dropped_by_capturer = 7; + stats.frames_dropped_by_encoder_queue = 8; + stats.frames_dropped_by_rate_limiter = 9; + stats.frames_dropped_by_congestion_window = 10; + stats.frames_dropped_by_encoder = 11; + stats.target_media_bitrate_bps = 13; + stats.media_bitrate_bps = 14; + stats.suspended = true; + stats.bw_limited_resolution = true; + stats.cpu_limited_resolution = true; + // Not wired. + stats.bw_limited_framerate = true; + // Not wired. + stats.cpu_limited_framerate = true; + stats.quality_limitation_reason = webrtc::QualityLimitationReason::kCpu; + stats.quality_limitation_durations_ms[webrtc::QualityLimitationReason::kCpu] = + 15; + stats.quality_limitation_resolution_changes = 16; + stats.number_of_cpu_adapt_changes = 17; + stats.number_of_quality_adapt_changes = 18; + stats.has_entered_low_resolution = true; + stats.content_type = webrtc::VideoContentType::SCREENSHARE; + stats.frames_sent = 19; + stats.huge_frames_sent = 20; + + return stats; +} + +TEST_F(WebRtcVideoChannelTest, GetAggregatedStatsReportWithoutSubStreams) { + FakeVideoSendStream* stream = AddSendStream(); + auto stats = GetInitialisedStats(); + stream->SetStats(stats); + cricket::VideoMediaInfo video_media_info; + ASSERT_TRUE(channel_->GetStats(&video_media_info)); + EXPECT_EQ(video_media_info.aggregated_senders.size(), 1u); + auto& sender = video_media_info.aggregated_senders[0]; + + // MediaSenderInfo + + EXPECT_EQ(sender.payload_bytes_sent, 0); + EXPECT_EQ(sender.header_and_padding_bytes_sent, 0); + EXPECT_EQ(sender.retransmitted_bytes_sent, 0u); + EXPECT_EQ(sender.packets_sent, 0); + EXPECT_EQ(sender.retransmitted_packets_sent, 0u); + EXPECT_EQ(sender.packets_lost, 0); + EXPECT_EQ(sender.fraction_lost, 0.0f); + EXPECT_EQ(sender.rtt_ms, 0); + EXPECT_EQ(sender.codec_name, DefaultCodec().name); + EXPECT_EQ(sender.codec_payload_type, DefaultCodec().id); + EXPECT_EQ(sender.local_stats.size(), 1u); + EXPECT_EQ(sender.local_stats[0].ssrc, last_ssrc_); + EXPECT_EQ(sender.local_stats[0].timestamp, 0.0f); + EXPECT_EQ(sender.remote_stats.size(), 0u); + EXPECT_EQ(sender.report_block_datas.size(), 0u); + + // VideoSenderInfo + + EXPECT_EQ(sender.ssrc_groups.size(), 0u); + EXPECT_EQ(sender.encoder_implementation_name, + stats.encoder_implementation_name); + // Comes from substream only. + EXPECT_EQ(sender.firs_rcvd, 0); + EXPECT_EQ(sender.plis_rcvd, 0); + EXPECT_EQ(sender.nacks_rcvd, 0); + EXPECT_EQ(sender.send_frame_width, 0); + EXPECT_EQ(sender.send_frame_height, 0); + + EXPECT_EQ(sender.framerate_input, stats.input_frame_rate); + EXPECT_EQ(sender.framerate_sent, stats.encode_frame_rate); + EXPECT_EQ(sender.nominal_bitrate, stats.media_bitrate_bps); + EXPECT_NE(sender.adapt_reason & WebRtcVideoChannel::ADAPTREASON_CPU, 0); + EXPECT_NE(sender.adapt_reason & WebRtcVideoChannel::ADAPTREASON_BANDWIDTH, 0); + EXPECT_EQ(sender.adapt_changes, stats.number_of_cpu_adapt_changes); + EXPECT_EQ(sender.quality_limitation_reason, stats.quality_limitation_reason); + EXPECT_EQ(sender.quality_limitation_durations_ms, + stats.quality_limitation_durations_ms); + EXPECT_EQ(sender.quality_limitation_resolution_changes, + stats.quality_limitation_resolution_changes); + EXPECT_EQ(sender.avg_encode_ms, stats.avg_encode_time_ms); + EXPECT_EQ(sender.encode_usage_percent, stats.encode_usage_percent); + EXPECT_EQ(sender.frames_encoded, stats.frames_encoded); + // Comes from substream only. + EXPECT_EQ(sender.key_frames_encoded, 0u); + + EXPECT_EQ(sender.total_encode_time_ms, stats.total_encode_time_ms); + EXPECT_EQ(sender.total_encoded_bytes_target, + stats.total_encoded_bytes_target); + // Comes from substream only. + EXPECT_EQ(sender.total_packet_send_delay_ms, 0u); + EXPECT_EQ(sender.qp_sum, absl::nullopt); + + EXPECT_EQ(sender.has_entered_low_resolution, + stats.has_entered_low_resolution); + EXPECT_EQ(sender.content_type, webrtc::VideoContentType::SCREENSHARE); + EXPECT_EQ(sender.frames_sent, stats.frames_encoded); + EXPECT_EQ(sender.huge_frames_sent, stats.huge_frames_sent); + EXPECT_EQ(sender.rid, absl::nullopt); +} + +TEST_F(WebRtcVideoChannelTest, GetAggregatedStatsReportForSubStreams) { + FakeVideoSendStream* stream = AddSendStream(); + auto stats = GetInitialisedStats(); + + const uint32_t ssrc_1 = 123u; + const uint32_t ssrc_2 = 456u; + + auto& substream = stats.substreams[ssrc_1]; + substream.frame_counts.key_frames = 1; + substream.frame_counts.delta_frames = 2; + substream.width = 3; + substream.height = 4; + substream.total_bitrate_bps = 5; + substream.retransmit_bitrate_bps = 6; + substream.avg_delay_ms = 7; + substream.max_delay_ms = 8; + substream.total_packet_send_delay_ms = 9; + substream.rtp_stats.transmitted.header_bytes = 10; + substream.rtp_stats.transmitted.padding_bytes = 11; + substream.rtp_stats.retransmitted.payload_bytes = 12; + substream.rtp_stats.retransmitted.packets = 13; + substream.rtcp_packet_type_counts.fir_packets = 14; + substream.rtcp_packet_type_counts.nack_packets = 15; + substream.rtcp_packet_type_counts.pli_packets = 16; + substream.rtcp_stats.packets_lost = 17; + substream.rtcp_stats.fraction_lost = 18; + webrtc::ReportBlockData report_block_data; + report_block_data.AddRoundTripTimeSample(19); + substream.report_block_data = report_block_data; + substream.encode_frame_rate = 20.0; + substream.frames_encoded = 21; + substream.qp_sum = 22; + substream.total_encode_time_ms = 23; + substream.total_encoded_bytes_target = 24; + substream.huge_frames_sent = 25; + + stats.substreams[ssrc_2] = substream; + + stream->SetStats(stats); + + cricket::VideoMediaInfo video_media_info; + ASSERT_TRUE(channel_->GetStats(&video_media_info)); + EXPECT_EQ(video_media_info.aggregated_senders.size(), 1u); + auto& sender = video_media_info.aggregated_senders[0]; + + // MediaSenderInfo + + EXPECT_EQ( + sender.payload_bytes_sent, + static_cast<int64_t>(2u * substream.rtp_stats.transmitted.payload_bytes)); + EXPECT_EQ(sender.header_and_padding_bytes_sent, + static_cast<int64_t>( + 2u * (substream.rtp_stats.transmitted.header_bytes + + substream.rtp_stats.transmitted.padding_bytes))); + EXPECT_EQ(sender.retransmitted_bytes_sent, + 2u * substream.rtp_stats.retransmitted.payload_bytes); + EXPECT_EQ(sender.packets_sent, + static_cast<int>(2 * substream.rtp_stats.transmitted.packets)); + EXPECT_EQ(sender.retransmitted_packets_sent, + 2u * substream.rtp_stats.retransmitted.packets); + EXPECT_EQ(sender.packets_lost, 2 * substream.rtcp_stats.packets_lost); + EXPECT_EQ(sender.fraction_lost, + static_cast<float>(substream.rtcp_stats.fraction_lost) / (1 << 8)); + EXPECT_EQ(sender.rtt_ms, 0); + EXPECT_EQ(sender.codec_name, DefaultCodec().name); + EXPECT_EQ(sender.codec_payload_type, DefaultCodec().id); + EXPECT_EQ(sender.local_stats.size(), 1u); + EXPECT_EQ(sender.local_stats[0].ssrc, last_ssrc_); + EXPECT_EQ(sender.local_stats[0].timestamp, 0.0f); + EXPECT_EQ(sender.remote_stats.size(), 0u); + EXPECT_EQ(sender.report_block_datas.size(), 2u * 1); + + // VideoSenderInfo + + EXPECT_EQ(sender.ssrc_groups.size(), 0u); + EXPECT_EQ(sender.encoder_implementation_name, + stats.encoder_implementation_name); + EXPECT_EQ( + sender.firs_rcvd, + static_cast<int>(2 * substream.rtcp_packet_type_counts.fir_packets)); + EXPECT_EQ( + sender.plis_rcvd, + static_cast<int>(2 * substream.rtcp_packet_type_counts.pli_packets)); + EXPECT_EQ( + sender.nacks_rcvd, + static_cast<int>(2 * substream.rtcp_packet_type_counts.nack_packets)); + EXPECT_EQ(sender.send_frame_width, substream.width); + EXPECT_EQ(sender.send_frame_height, substream.height); + + EXPECT_EQ(sender.framerate_input, stats.input_frame_rate); + EXPECT_EQ(sender.framerate_sent, stats.encode_frame_rate); + EXPECT_EQ(sender.nominal_bitrate, stats.media_bitrate_bps); + EXPECT_NE(sender.adapt_reason & WebRtcVideoChannel::ADAPTREASON_CPU, 0); + EXPECT_NE(sender.adapt_reason & WebRtcVideoChannel::ADAPTREASON_BANDWIDTH, 0); + EXPECT_EQ(sender.adapt_changes, stats.number_of_cpu_adapt_changes); + EXPECT_EQ(sender.quality_limitation_reason, stats.quality_limitation_reason); + EXPECT_EQ(sender.quality_limitation_durations_ms, + stats.quality_limitation_durations_ms); + EXPECT_EQ(sender.quality_limitation_resolution_changes, + stats.quality_limitation_resolution_changes); + EXPECT_EQ(sender.avg_encode_ms, stats.avg_encode_time_ms); + EXPECT_EQ(sender.encode_usage_percent, stats.encode_usage_percent); + EXPECT_EQ(sender.frames_encoded, 2u * substream.frames_encoded); + EXPECT_EQ(sender.key_frames_encoded, 2u * substream.frame_counts.key_frames); + EXPECT_EQ(sender.total_encode_time_ms, 2u * substream.total_encode_time_ms); + EXPECT_EQ(sender.total_encoded_bytes_target, + 2u * substream.total_encoded_bytes_target); + EXPECT_EQ(sender.total_packet_send_delay_ms, + 2u * substream.total_packet_send_delay_ms); + EXPECT_EQ(sender.has_entered_low_resolution, + stats.has_entered_low_resolution); + EXPECT_EQ(sender.qp_sum, 2u * *substream.qp_sum); + EXPECT_EQ(sender.content_type, webrtc::VideoContentType::SCREENSHARE); + EXPECT_EQ(sender.frames_sent, 2u * substream.frames_encoded); + EXPECT_EQ(sender.huge_frames_sent, stats.huge_frames_sent); + EXPECT_EQ(sender.rid, absl::nullopt); +} + +TEST_F(WebRtcVideoChannelTest, GetPerLayerStatsReportForSubStreams) { + FakeVideoSendStream* stream = AddSendStream(); + auto stats = GetInitialisedStats(); + + const uint32_t ssrc_1 = 123u; + const uint32_t ssrc_2 = 456u; + + auto& substream = stats.substreams[ssrc_1]; + substream.frame_counts.key_frames = 1; + substream.frame_counts.delta_frames = 2; + substream.width = 3; + substream.height = 4; + substream.total_bitrate_bps = 5; + substream.retransmit_bitrate_bps = 6; + substream.avg_delay_ms = 7; + substream.max_delay_ms = 8; + substream.total_packet_send_delay_ms = 9; + substream.rtp_stats.transmitted.header_bytes = 10; + substream.rtp_stats.transmitted.padding_bytes = 11; + substream.rtp_stats.retransmitted.payload_bytes = 12; + substream.rtp_stats.retransmitted.packets = 13; + substream.rtcp_packet_type_counts.fir_packets = 14; + substream.rtcp_packet_type_counts.nack_packets = 15; + substream.rtcp_packet_type_counts.pli_packets = 16; + substream.rtcp_stats.packets_lost = 17; + substream.rtcp_stats.fraction_lost = 18; + webrtc::ReportBlockData report_block_data; + report_block_data.AddRoundTripTimeSample(19); + substream.report_block_data = report_block_data; + substream.encode_frame_rate = 20.0; + substream.frames_encoded = 21; + substream.qp_sum = 22; + substream.total_encode_time_ms = 23; + substream.total_encoded_bytes_target = 24; + substream.huge_frames_sent = 25; + + stats.substreams[ssrc_2] = substream; + + stream->SetStats(stats); + + cricket::VideoMediaInfo video_media_info; + ASSERT_TRUE(channel_->GetStats(&video_media_info)); + EXPECT_EQ(video_media_info.senders.size(), 2u); + auto& sender = video_media_info.senders[0]; + + // MediaSenderInfo + + EXPECT_EQ( + sender.payload_bytes_sent, + static_cast<int64_t>(substream.rtp_stats.transmitted.payload_bytes)); + EXPECT_EQ( + sender.header_and_padding_bytes_sent, + static_cast<int64_t>(substream.rtp_stats.transmitted.header_bytes + + substream.rtp_stats.transmitted.padding_bytes)); + EXPECT_EQ(sender.retransmitted_bytes_sent, + substream.rtp_stats.retransmitted.payload_bytes); + EXPECT_EQ(sender.packets_sent, + static_cast<int>(substream.rtp_stats.transmitted.packets)); + EXPECT_EQ(sender.retransmitted_packets_sent, + substream.rtp_stats.retransmitted.packets); + EXPECT_EQ(sender.packets_lost, substream.rtcp_stats.packets_lost); + EXPECT_EQ(sender.fraction_lost, + static_cast<float>(substream.rtcp_stats.fraction_lost) / (1 << 8)); + EXPECT_EQ(sender.rtt_ms, 0); + EXPECT_EQ(sender.codec_name, DefaultCodec().name); + EXPECT_EQ(sender.codec_payload_type, DefaultCodec().id); + EXPECT_EQ(sender.local_stats.size(), 1u); + EXPECT_EQ(sender.local_stats[0].ssrc, ssrc_1); + EXPECT_EQ(sender.local_stats[0].timestamp, 0.0f); + EXPECT_EQ(sender.remote_stats.size(), 0u); + EXPECT_EQ(sender.report_block_datas.size(), 1u); + + // VideoSenderInfo + + EXPECT_EQ(sender.ssrc_groups.size(), 0u); + EXPECT_EQ(sender.encoder_implementation_name, + stats.encoder_implementation_name); + EXPECT_EQ(sender.firs_rcvd, + static_cast<int>(substream.rtcp_packet_type_counts.fir_packets)); + EXPECT_EQ(sender.plis_rcvd, + static_cast<int>(substream.rtcp_packet_type_counts.pli_packets)); + EXPECT_EQ(sender.nacks_rcvd, + static_cast<int>(substream.rtcp_packet_type_counts.nack_packets)); + EXPECT_EQ(sender.send_frame_width, substream.width); + EXPECT_EQ(sender.send_frame_height, substream.height); + + EXPECT_EQ(sender.framerate_input, stats.input_frame_rate); + EXPECT_EQ(sender.framerate_sent, substream.encode_frame_rate); + EXPECT_EQ(sender.nominal_bitrate, stats.media_bitrate_bps); + EXPECT_NE(sender.adapt_reason & WebRtcVideoChannel::ADAPTREASON_CPU, 0); + EXPECT_NE(sender.adapt_reason & WebRtcVideoChannel::ADAPTREASON_BANDWIDTH, 0); + EXPECT_EQ(sender.adapt_changes, stats.number_of_cpu_adapt_changes); + EXPECT_EQ(sender.quality_limitation_reason, stats.quality_limitation_reason); + EXPECT_EQ(sender.quality_limitation_durations_ms, + stats.quality_limitation_durations_ms); + EXPECT_EQ(sender.quality_limitation_resolution_changes, + stats.quality_limitation_resolution_changes); + EXPECT_EQ(sender.avg_encode_ms, stats.avg_encode_time_ms); + EXPECT_EQ(sender.encode_usage_percent, stats.encode_usage_percent); + EXPECT_EQ(sender.frames_encoded, + static_cast<uint32_t>(substream.frames_encoded)); + EXPECT_EQ(sender.key_frames_encoded, + static_cast<uint32_t>(substream.frame_counts.key_frames)); + EXPECT_EQ(sender.total_encode_time_ms, substream.total_encode_time_ms); + EXPECT_EQ(sender.total_encoded_bytes_target, + substream.total_encoded_bytes_target); + EXPECT_EQ(sender.total_packet_send_delay_ms, + substream.total_packet_send_delay_ms); + EXPECT_EQ(sender.has_entered_low_resolution, + stats.has_entered_low_resolution); + EXPECT_EQ(sender.qp_sum, *substream.qp_sum); + EXPECT_EQ(sender.content_type, webrtc::VideoContentType::SCREENSHARE); + EXPECT_EQ(sender.frames_sent, + static_cast<uint32_t>(substream.frames_encoded)); + EXPECT_EQ(sender.huge_frames_sent, substream.huge_frames_sent); + EXPECT_EQ(sender.rid, absl::nullopt); } TEST_F(WebRtcVideoChannelTest, GetStatsReportsUpperResolution) { @@ -5248,9 +5608,16 @@ TEST_F(WebRtcVideoChannelTest, GetStatsReportsUpperResolution) { cricket::VideoMediaInfo info; ASSERT_TRUE(channel_->GetStats(&info)); - ASSERT_EQ(1u, info.senders.size()); - EXPECT_EQ(123, info.senders[0].send_frame_width); + ASSERT_EQ(1u, info.aggregated_senders.size()); + ASSERT_EQ(3u, info.senders.size()); + EXPECT_EQ(123, info.senders[1].send_frame_width); + EXPECT_EQ(40, info.senders[1].send_frame_height); + EXPECT_EQ(80, info.senders[2].send_frame_width); + EXPECT_EQ(31, info.senders[2].send_frame_height); + EXPECT_EQ(20, info.senders[0].send_frame_width); EXPECT_EQ(90, info.senders[0].send_frame_height); + EXPECT_EQ(123, info.aggregated_senders[0].send_frame_width); + EXPECT_EQ(90, info.aggregated_senders[0].send_frame_height); } TEST_F(WebRtcVideoChannelTest, GetStatsReportsCpuAdaptationStats) { @@ -5448,19 +5815,18 @@ TEST_F(WebRtcVideoChannelTest, cricket::VideoMediaInfo info; ASSERT_TRUE(channel_->GetStats(&info)); - // TODO(https://crbug.com/webrtc/9547): Populate individual VideoSenderInfo - // objects for each simulcast stream, instead of accumulating all layers into - // a single VideoSenderInfo. When this is fixed, this test should expect that - // there are two VideoSenderInfo, where the first info accounts for the first - // RTX and the second info accounts for the second RTX. In order for the test - // to be set up correctly, it may need to be updated such that the - // relationship between RTP and RTX streams are known. See also - // https://crbug.com/webrtc/11439. - EXPECT_EQ(60u, info.senders[0].header_and_padding_bytes_sent); - EXPECT_EQ(107u, info.senders[0].payload_bytes_sent); - EXPECT_EQ(20, info.senders[0].packets_sent); - EXPECT_EQ(30u, info.senders[0].retransmitted_bytes_sent); - EXPECT_EQ(5u, info.senders[0].retransmitted_packets_sent); + EXPECT_EQ(info.senders.size(), 2u); + EXPECT_EQ(15u, info.senders[0].header_and_padding_bytes_sent); + EXPECT_EQ(30u, info.senders[0].payload_bytes_sent); + EXPECT_EQ(4, info.senders[0].packets_sent); + EXPECT_EQ(10u, info.senders[0].retransmitted_bytes_sent); + EXPECT_EQ(1u, info.senders[0].retransmitted_packets_sent); + + EXPECT_EQ(45u, info.senders[1].header_and_padding_bytes_sent); + EXPECT_EQ(77u, info.senders[1].payload_bytes_sent); + EXPECT_EQ(16, info.senders[1].packets_sent); + EXPECT_EQ(20u, info.senders[1].retransmitted_bytes_sent); + EXPECT_EQ(4u, info.senders[1].retransmitted_packets_sent); } TEST_F(WebRtcVideoChannelTest, @@ -5492,9 +5858,17 @@ TEST_F(WebRtcVideoChannelTest, GetStatsTranslatesSendRtcpPacketTypesCorrectly) { cricket::VideoMediaInfo info; ASSERT_TRUE(channel_->GetStats(&info)); - EXPECT_EQ(7, info.senders[0].firs_rcvd); - EXPECT_EQ(10, info.senders[0].nacks_rcvd); - EXPECT_EQ(13, info.senders[0].plis_rcvd); + EXPECT_EQ(2, info.senders[0].firs_rcvd); + EXPECT_EQ(3, info.senders[0].nacks_rcvd); + EXPECT_EQ(4, info.senders[0].plis_rcvd); + + EXPECT_EQ(5, info.senders[1].firs_rcvd); + EXPECT_EQ(7, info.senders[1].nacks_rcvd); + EXPECT_EQ(9, info.senders[1].plis_rcvd); + + EXPECT_EQ(7, info.aggregated_senders[0].firs_rcvd); + EXPECT_EQ(10, info.aggregated_senders[0].nacks_rcvd); + EXPECT_EQ(13, info.aggregated_senders[0].plis_rcvd); } TEST_F(WebRtcVideoChannelTest, @@ -5639,13 +6013,16 @@ TEST_F(WebRtcVideoChannelTest, TranslatesSenderBitrateStatsCorrectly) { cricket::VideoMediaInfo info; ASSERT_TRUE(channel_->GetStats(&info)); - ASSERT_EQ(2u, info.senders.size()); + ASSERT_EQ(2u, info.aggregated_senders.size()); + ASSERT_EQ(4u, info.senders.size()); BandwidthEstimationInfo bwe_info; channel_->FillBitrateInfo(&bwe_info); // Assuming stream and stream2 corresponds to senders[0] and [1] respectively // is OK as std::maps are sorted and AddSendStream() gives increasing SSRCs. - EXPECT_EQ(stats.media_bitrate_bps, info.senders[0].nominal_bitrate); - EXPECT_EQ(stats2.media_bitrate_bps, info.senders[1].nominal_bitrate); + EXPECT_EQ(stats.media_bitrate_bps, + info.aggregated_senders[0].nominal_bitrate); + EXPECT_EQ(stats2.media_bitrate_bps, + info.aggregated_senders[1].nominal_bitrate); EXPECT_EQ(stats.target_media_bitrate_bps + stats2.target_media_bitrate_bps, bwe_info.target_enc_bitrate); EXPECT_EQ(stats.media_bitrate_bps + stats2.media_bitrate_bps, |