Add power efficient stats to RTC stats

As the exposure of power efficient stats to JavaScript are limited as
to reduce the fingerprinting surface to getStats, a new RTCStatsMember
derivation, RTCLimitedStatsMember, was added in this change. This sets
the exposure criteria of the stat on the type, which keeps the size of
the RTCStatsMember class the same and allows for extension in the future
for new types of stat restrictions.

Bug: webrtc:14483
Change-Id: Ib0303050a112441ba2416fd5f004dd8be26b47ca
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/279021
Commit-Queue: Evan Shrubsole <eshr@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#38576}
This commit is contained in:
Evan Shrubsole 2022-10-31 11:03:10 +00:00 committed by WebRTC LUCI CQ
parent b456788d44
commit 13c0be44b3
5 changed files with 36 additions and 2 deletions

View File

@ -496,6 +496,8 @@ class RTC_EXPORT RTCInboundRTPStreamStats final
// TimingFrameInfo::ToString(). // TimingFrameInfo::ToString().
// TODO(https://crbug.com/webrtc/14586): Unship or standardize this metric. // TODO(https://crbug.com/webrtc/14586): Unship or standardize this metric.
RTCStatsMember<std::string> goog_timing_frame_info; RTCStatsMember<std::string> goog_timing_frame_info;
RTCRestrictedStatsMember<bool, StatExposureCriteria::kHardwareCapability>
power_efficient_decoder;
// Non-standard audio metrics. // Non-standard audio metrics.
RTCNonStandardStatsMember<uint64_t> jitter_buffer_flushes; RTCNonStandardStatsMember<uint64_t> jitter_buffer_flushes;
RTCNonStandardStatsMember<uint64_t> delayed_packet_outage_samples; RTCNonStandardStatsMember<uint64_t> delayed_packet_outage_samples;
@ -553,6 +555,8 @@ class RTC_EXPORT RTCOutboundRTPStreamStats final : public RTCRTPStreamStats {
RTCStatsMember<uint32_t> nack_count; RTCStatsMember<uint32_t> nack_count;
RTCStatsMember<uint64_t> qp_sum; RTCStatsMember<uint64_t> qp_sum;
RTCStatsMember<bool> active; RTCStatsMember<bool> active;
RTCRestrictedStatsMember<bool, StatExposureCriteria::kHardwareCapability>
power_efficient_encoder;
}; };
// https://w3c.github.io/webrtc-stats/#remoteinboundrtpstats-dict* // https://w3c.github.io/webrtc-stats/#remoteinboundrtpstats-dict*

View File

@ -654,6 +654,10 @@ void SetInboundRTPStreamStatsFromVideoReceiverInfo(
inbound_video->decoder_implementation = inbound_video->decoder_implementation =
video_receiver_info.decoder_implementation_name; video_receiver_info.decoder_implementation_name;
} }
if (video_receiver_info.power_efficient_decoder.has_value()) {
inbound_video->power_efficient_decoder =
video_receiver_info.power_efficient_decoder.value();
}
} }
// Provides the media independent counters and information (both audio and // Provides the media independent counters and information (both audio and
@ -784,6 +788,10 @@ void SetOutboundRTPStreamStatsFromVideoSenderInfo(
if (video_sender_info.rid.has_value()) { if (video_sender_info.rid.has_value()) {
outbound_video->rid = *video_sender_info.rid; outbound_video->rid = *video_sender_info.rid;
} }
if (video_sender_info.power_efficient_encoder.has_value()) {
outbound_video->power_efficient_encoder =
video_sender_info.power_efficient_encoder.value();
}
} }
std::unique_ptr<RTCRemoteInboundRtpStreamStats> std::unique_ptr<RTCRemoteInboundRtpStreamStats>

View File

@ -2597,6 +2597,7 @@ TEST_F(RTCStatsCollectorTest, CollectRTCInboundRTPStreamStats_Video) {
absl::nullopt; absl::nullopt;
video_media_info.receivers[0].decoder_implementation_name = ""; video_media_info.receivers[0].decoder_implementation_name = "";
video_media_info.receivers[0].min_playout_delay_ms = 50; video_media_info.receivers[0].min_playout_delay_ms = 50;
video_media_info.receivers[0].power_efficient_decoder = false;
// Note: these two values intentionally differ, // Note: these two values intentionally differ,
// only the decoded one should show up. // only the decoded one should show up.
@ -2661,6 +2662,7 @@ TEST_F(RTCStatsCollectorTest, CollectRTCInboundRTPStreamStats_Video) {
// `expected_video.decoder_implementation` should be undefined. // `expected_video.decoder_implementation` should be undefined.
expected_video.min_playout_delay = 0.05; expected_video.min_playout_delay = 0.05;
expected_video.frames_per_second = 5; expected_video.frames_per_second = 5;
expected_video.power_efficient_decoder = false;
ASSERT_TRUE(report->Get(expected_video.id())); ASSERT_TRUE(report->Get(expected_video.id()));
EXPECT_EQ( EXPECT_EQ(
@ -2678,6 +2680,8 @@ TEST_F(RTCStatsCollectorTest, CollectRTCInboundRTPStreamStats_Video) {
expected_video.estimated_playout_timestamp = 1234; expected_video.estimated_playout_timestamp = 1234;
video_media_info.receivers[0].decoder_implementation_name = "libfoodecoder"; video_media_info.receivers[0].decoder_implementation_name = "libfoodecoder";
expected_video.decoder_implementation = "libfoodecoder"; expected_video.decoder_implementation = "libfoodecoder";
video_media_info.receivers[0].power_efficient_decoder = true;
expected_video.power_efficient_decoder = true;
video_media_channel->SetStats(video_media_info); video_media_channel->SetStats(video_media_info);
report = stats_->GetFreshStatsReport(); report = stats_->GetFreshStatsReport();
@ -2824,6 +2828,7 @@ TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRTPStreamStats_Video) {
video_media_info.senders[0].qp_sum = absl::nullopt; video_media_info.senders[0].qp_sum = absl::nullopt;
video_media_info.senders[0].content_type = VideoContentType::UNSPECIFIED; video_media_info.senders[0].content_type = VideoContentType::UNSPECIFIED;
video_media_info.senders[0].encoder_implementation_name = ""; video_media_info.senders[0].encoder_implementation_name = "";
video_media_info.senders[0].power_efficient_encoder = false;
video_media_info.senders[0].send_frame_width = 200; video_media_info.senders[0].send_frame_width = 200;
video_media_info.senders[0].send_frame_height = 100; video_media_info.senders[0].send_frame_height = 100;
video_media_info.senders[0].framerate_sent = 10; video_media_info.senders[0].framerate_sent = 10;
@ -2888,6 +2893,7 @@ TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRTPStreamStats_Video) {
expected_video.frames_sent = 5; expected_video.frames_sent = 5;
expected_video.huge_frames_sent = 2; expected_video.huge_frames_sent = 2;
expected_video.active = false; expected_video.active = false;
expected_video.power_efficient_encoder = false;
// `expected_video.content_type` should be undefined. // `expected_video.content_type` should be undefined.
// `expected_video.qp_sum` should be undefined. // `expected_video.qp_sum` should be undefined.
// `expected_video.encoder_implementation` should be undefined. // `expected_video.encoder_implementation` should be undefined.
@ -2905,6 +2911,8 @@ TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRTPStreamStats_Video) {
video_media_info.senders[0].encoder_implementation_name = "libfooencoder"; video_media_info.senders[0].encoder_implementation_name = "libfooencoder";
video_media_info.aggregated_senders[0] = video_media_info.senders[0]; video_media_info.aggregated_senders[0] = video_media_info.senders[0];
expected_video.encoder_implementation = "libfooencoder"; expected_video.encoder_implementation = "libfooencoder";
video_media_info.senders[0].power_efficient_encoder = true;
expected_video.power_efficient_encoder = true;
video_media_channel->SetStats(video_media_info); video_media_channel->SetStats(video_media_info);
report = stats_->GetFreshStatsReport(); report = stats_->GetFreshStatsReport();

View File

@ -750,9 +750,15 @@ class RTCStatsReportVerifier {
if (inbound_stream.kind.is_defined() && *inbound_stream.kind == "video") { if (inbound_stream.kind.is_defined() && *inbound_stream.kind == "video") {
verifier.TestMemberIsNonNegative<uint64_t>(inbound_stream.qp_sum); verifier.TestMemberIsNonNegative<uint64_t>(inbound_stream.qp_sum);
verifier.TestMemberIsDefined(inbound_stream.decoder_implementation); verifier.TestMemberIsDefined(inbound_stream.decoder_implementation);
verifier.TestMemberIsDefined(inbound_stream.power_efficient_decoder);
EXPECT_EQ(inbound_stream.power_efficient_decoder.exposure_criteria(),
StatExposureCriteria::kHardwareCapability);
} else { } else {
verifier.TestMemberIsUndefined(inbound_stream.qp_sum); verifier.TestMemberIsUndefined(inbound_stream.qp_sum);
verifier.TestMemberIsUndefined(inbound_stream.decoder_implementation); verifier.TestMemberIsUndefined(inbound_stream.decoder_implementation);
verifier.TestMemberIsUndefined(inbound_stream.power_efficient_decoder);
EXPECT_EQ(inbound_stream.power_efficient_decoder.exposure_criteria(),
StatExposureCriteria::kHardwareCapability);
} }
verifier.TestMemberIsNonNegative<uint32_t>(inbound_stream.packets_received); verifier.TestMemberIsNonNegative<uint32_t>(inbound_stream.packets_received);
if (inbound_stream.kind.is_defined() && *inbound_stream.kind == "audio") { if (inbound_stream.kind.is_defined() && *inbound_stream.kind == "audio") {
@ -958,6 +964,9 @@ class RTCStatsReportVerifier {
// this to be present. // this to be present.
verifier.MarkMemberTested(outbound_stream.content_type, true); verifier.MarkMemberTested(outbound_stream.content_type, true);
verifier.TestMemberIsDefined(outbound_stream.encoder_implementation); verifier.TestMemberIsDefined(outbound_stream.encoder_implementation);
verifier.TestMemberIsDefined(outbound_stream.power_efficient_encoder);
EXPECT_EQ(outbound_stream.power_efficient_encoder.exposure_criteria(),
StatExposureCriteria::kHardwareCapability);
// Unless an implementation-specific amount of time has passed and at // Unless an implementation-specific amount of time has passed and at
// least one frame has been encoded, undefined is reported. Because it // least one frame has been encoded, undefined is reported. Because it
// is hard to tell what is the case here, we treat FPS as optional. // is hard to tell what is the case here, we treat FPS as optional.
@ -989,6 +998,7 @@ class RTCStatsReportVerifier {
verifier.TestMemberIsUndefined(outbound_stream.content_type); verifier.TestMemberIsUndefined(outbound_stream.content_type);
// TODO(hbos): Implement for audio as well. // TODO(hbos): Implement for audio as well.
verifier.TestMemberIsUndefined(outbound_stream.encoder_implementation); verifier.TestMemberIsUndefined(outbound_stream.encoder_implementation);
verifier.TestMemberIsUndefined(outbound_stream.power_efficient_encoder);
verifier.TestMemberIsUndefined(outbound_stream.rid); verifier.TestMemberIsUndefined(outbound_stream.rid);
verifier.TestMemberIsUndefined(outbound_stream.frames_per_second); verifier.TestMemberIsUndefined(outbound_stream.frames_per_second);
verifier.TestMemberIsUndefined(outbound_stream.frame_height); verifier.TestMemberIsUndefined(outbound_stream.frame_height);

View File

@ -561,6 +561,7 @@ WEBRTC_RTCSTATS_IMPL(
&nack_count, &nack_count,
&qp_sum, &qp_sum,
&goog_timing_frame_info, &goog_timing_frame_info,
&power_efficient_decoder,
&jitter_buffer_flushes, &jitter_buffer_flushes,
&delayed_packet_outage_samples, &delayed_packet_outage_samples,
&relative_packet_arrival_delay, &relative_packet_arrival_delay,
@ -625,6 +626,7 @@ RTCInboundRTPStreamStats::RTCInboundRTPStreamStats(std::string&& id,
nack_count("nackCount"), nack_count("nackCount"),
qp_sum("qpSum"), qp_sum("qpSum"),
goog_timing_frame_info("googTimingFrameInfo"), goog_timing_frame_info("googTimingFrameInfo"),
power_efficient_decoder("powerEfficientDecoder"),
jitter_buffer_flushes( jitter_buffer_flushes(
"jitterBufferFlushes", "jitterBufferFlushes",
{NonStandardGroupId::kRtcAudioJitterBufferMaxPackets}), {NonStandardGroupId::kRtcAudioJitterBufferMaxPackets}),
@ -675,7 +677,8 @@ WEBRTC_RTCSTATS_IMPL(
&pli_count, &pli_count,
&nack_count, &nack_count,
&qp_sum, &qp_sum,
&active) &active,
&power_efficient_encoder)
// clang-format on // clang-format on
RTCOutboundRTPStreamStats::RTCOutboundRTPStreamStats(const std::string& id, RTCOutboundRTPStreamStats::RTCOutboundRTPStreamStats(const std::string& id,
@ -715,7 +718,8 @@ RTCOutboundRTPStreamStats::RTCOutboundRTPStreamStats(std::string&& id,
pli_count("pliCount"), pli_count("pliCount"),
nack_count("nackCount"), nack_count("nackCount"),
qp_sum("qpSum"), qp_sum("qpSum"),
active("active") {} active("active"),
power_efficient_encoder("powerEfficientEncoder") {}
RTCOutboundRTPStreamStats::RTCOutboundRTPStreamStats( RTCOutboundRTPStreamStats::RTCOutboundRTPStreamStats(
const RTCOutboundRTPStreamStats& other) = default; const RTCOutboundRTPStreamStats& other) = default;