aboutsummaryrefslogtreecommitdiff
path: root/media
diff options
context:
space:
mode:
authorHenrik Boström <hbos@webrtc.org>2020-05-05 15:54:46 +0200
committerCommit Bot <commit-bot@chromium.org>2020-05-05 20:22:19 +0000
commita0ff50c0318396f65f25a4ea9e7803858aa84ea7 (patch)
tree3ed2abeb58c1ee0aaf95606e8df0132b964c1656 /media
parentc0df5fc25b82fc5a2071be55e5357ce786caf637 (diff)
downloadwebrtc-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.h13
-rw-r--r--media/engine/webrtc_video_engine.cc232
-rw-r--r--media/engine/webrtc_video_engine.h7
-rw-r--r--media/engine/webrtc_video_engine_unittest.cc433
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,