1 /*
2 * Copyright 2018 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "absl/types/optional.h"
12 #include "api/test/video/function_video_encoder_factory.h"
13 #include "modules/video_coding/codecs/vp8/include/vp8.h"
14 #include "rtc_base/synchronization/mutex.h"
15 #include "system_wrappers/include/metrics.h"
16 #include "test/call_test.h"
17 #include "test/gtest.h"
18
19 namespace webrtc {
20 namespace {
21 enum : int { // The first valid value is 1.
22 kTransportSequenceNumberExtensionId = 1,
23 kVideoContentTypeExtensionId,
24 };
25 } // namespace
26
27 class HistogramTest : public test::CallTest {
28 public:
HistogramTest()29 HistogramTest() {
30 RegisterRtpExtension(RtpExtension(RtpExtension::kTransportSequenceNumberUri,
31 kTransportSequenceNumberExtensionId));
32 RegisterRtpExtension(RtpExtension(RtpExtension::kVideoContentTypeUri,
33 kVideoContentTypeExtensionId));
34 }
35
36 protected:
37 void VerifyHistogramStats(bool use_rtx, bool use_fec, bool screenshare);
38 };
39
VerifyHistogramStats(bool use_rtx,bool use_fec,bool screenshare)40 void HistogramTest::VerifyHistogramStats(bool use_rtx,
41 bool use_fec,
42 bool screenshare) {
43 class FrameObserver : public test::EndToEndTest,
44 public rtc::VideoSinkInterface<VideoFrame> {
45 public:
46 FrameObserver(bool use_rtx, bool use_fec, bool screenshare)
47 : EndToEndTest(kLongTimeout),
48 use_rtx_(use_rtx),
49 use_fec_(use_fec),
50 screenshare_(screenshare),
51 // This test uses NACK, so to send FEC we can't use a fake encoder.
52 encoder_factory_([]() { return VP8Encoder::Create(); }),
53 num_frames_received_(0) {}
54
55 private:
56 void OnFrame(const VideoFrame& video_frame) override {
57 // The RTT is needed to estimate `ntp_time_ms` which is used by
58 // end-to-end delay stats. Therefore, start counting received frames once
59 // `ntp_time_ms` is valid.
60 if (video_frame.ntp_time_ms() > 0 &&
61 Clock::GetRealTimeClock()->CurrentNtpInMilliseconds() >=
62 video_frame.ntp_time_ms()) {
63 MutexLock lock(&mutex_);
64 ++num_frames_received_;
65 }
66 }
67
68 Action OnSendRtp(const uint8_t* packet, size_t length) override {
69 if (MinMetricRunTimePassed() && MinNumberOfFramesReceived())
70 observation_complete_.Set();
71
72 return SEND_PACKET;
73 }
74
75 bool MinMetricRunTimePassed() {
76 int64_t now_ms = Clock::GetRealTimeClock()->TimeInMilliseconds();
77 if (!start_runtime_ms_)
78 start_runtime_ms_ = now_ms;
79
80 int64_t elapsed_sec = (now_ms - *start_runtime_ms_) / 1000;
81 return elapsed_sec > metrics::kMinRunTimeInSeconds * 2;
82 }
83
84 bool MinNumberOfFramesReceived() const {
85 const int kMinRequiredHistogramSamples = 200;
86 MutexLock lock(&mutex_);
87 return num_frames_received_ > kMinRequiredHistogramSamples;
88 }
89
90 void ModifyVideoConfigs(
91 VideoSendStream::Config* send_config,
92 std::vector<VideoReceiveStreamInterface::Config>* receive_configs,
93 VideoEncoderConfig* encoder_config) override {
94 // NACK
95 send_config->rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
96 (*receive_configs)[0].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
97 (*receive_configs)[0].renderer = this;
98 // FEC
99 if (use_fec_) {
100 send_config->rtp.ulpfec.ulpfec_payload_type = kUlpfecPayloadType;
101 send_config->rtp.ulpfec.red_payload_type = kRedPayloadType;
102 send_config->encoder_settings.encoder_factory = &encoder_factory_;
103 send_config->rtp.payload_name = "VP8";
104 encoder_config->codec_type = kVideoCodecVP8;
105 (*receive_configs)[0].decoders[0].video_format = SdpVideoFormat("VP8");
106 (*receive_configs)[0].rtp.red_payload_type = kRedPayloadType;
107 (*receive_configs)[0].rtp.ulpfec_payload_type = kUlpfecPayloadType;
108 }
109 // RTX
110 if (use_rtx_) {
111 send_config->rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[0]);
112 send_config->rtp.rtx.payload_type = kSendRtxPayloadType;
113 (*receive_configs)[0].rtp.rtx_ssrc = kSendRtxSsrcs[0];
114 (*receive_configs)[0]
115 .rtp.rtx_associated_payload_types[kSendRtxPayloadType] =
116 kFakeVideoSendPayloadType;
117 if (use_fec_) {
118 send_config->rtp.ulpfec.red_rtx_payload_type = kRtxRedPayloadType;
119 (*receive_configs)[0]
120 .rtp.rtx_associated_payload_types[kRtxRedPayloadType] =
121 kSendRtxPayloadType;
122 }
123 }
124 // RTT needed for RemoteNtpTimeEstimator for the receive stream.
125 (*receive_configs)[0].rtp.rtcp_xr.receiver_reference_time_report = true;
126 encoder_config->content_type =
127 screenshare_ ? VideoEncoderConfig::ContentType::kScreen
128 : VideoEncoderConfig::ContentType::kRealtimeVideo;
129 }
130
131 void PerformTest() override {
132 EXPECT_TRUE(Wait()) << "Timed out waiting for min frames to be received.";
133 }
134
135 mutable Mutex mutex_;
136 const bool use_rtx_;
137 const bool use_fec_;
138 const bool screenshare_;
139 test::FunctionVideoEncoderFactory encoder_factory_;
140 absl::optional<int64_t> start_runtime_ms_;
141 int num_frames_received_ RTC_GUARDED_BY(&mutex_);
142 } test(use_rtx, use_fec, screenshare);
143
144 metrics::Reset();
145 RunBaseTest(&test);
146
147 const std::string video_prefix =
148 screenshare ? "WebRTC.Video.Screenshare." : "WebRTC.Video.";
149 // The content type extension is disabled in non screenshare test,
150 // therefore no slicing on simulcast id should be present.
151 const std::string video_suffix = screenshare ? ".S0" : "";
152
153 // Verify that stats have been updated once.
154 EXPECT_METRIC_EQ(2, metrics::NumSamples("WebRTC.Call.LifetimeInSeconds"));
155 EXPECT_METRIC_EQ(1, metrics::NumSamples(
156 "WebRTC.Call.TimeReceivingVideoRtpPacketsInSeconds"));
157 EXPECT_METRIC_EQ(
158 1, metrics::NumSamples("WebRTC.Call.VideoBitrateReceivedInKbps"));
159 EXPECT_METRIC_EQ(1,
160 metrics::NumSamples("WebRTC.Call.RtcpBitrateReceivedInBps"));
161 EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Call.BitrateReceivedInKbps"));
162 EXPECT_METRIC_EQ(
163 1, metrics::NumSamples("WebRTC.Call.EstimatedSendBitrateInKbps"));
164 EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Call.PacerBitrateInKbps"));
165
166 EXPECT_METRIC_EQ(
167 1, metrics::NumSamples("WebRTC.Video.SendStreamLifetimeInSeconds"));
168 EXPECT_METRIC_EQ(
169 1, metrics::NumSamples("WebRTC.Video.ReceiveStreamLifetimeInSeconds"));
170
171 EXPECT_METRIC_EQ(
172 1, metrics::NumSamples("WebRTC.Video.NackPacketsSentPerMinute"));
173 EXPECT_METRIC_EQ(
174 1, metrics::NumSamples(video_prefix + "NackPacketsReceivedPerMinute"));
175 EXPECT_METRIC_EQ(1,
176 metrics::NumSamples("WebRTC.Video.FirPacketsSentPerMinute"));
177 EXPECT_METRIC_EQ(
178 1, metrics::NumSamples(video_prefix + "FirPacketsReceivedPerMinute"));
179 EXPECT_METRIC_EQ(1,
180 metrics::NumSamples("WebRTC.Video.PliPacketsSentPerMinute"));
181 EXPECT_METRIC_EQ(
182 1, metrics::NumSamples(video_prefix + "PliPacketsReceivedPerMinute"));
183
184 EXPECT_METRIC_EQ(
185 1, metrics::NumSamples(video_prefix + "KeyFramesSentInPermille"));
186 EXPECT_METRIC_EQ(
187 1, metrics::NumSamples("WebRTC.Video.KeyFramesReceivedInPermille"));
188
189 EXPECT_METRIC_EQ(
190 1, metrics::NumSamples(video_prefix + "SentPacketsLostInPercent"));
191 EXPECT_METRIC_EQ(
192 1, metrics::NumSamples("WebRTC.Video.ReceivedPacketsLostInPercent"));
193
194 EXPECT_METRIC_EQ(1, metrics::NumSamples(video_prefix + "InputWidthInPixels"));
195 EXPECT_METRIC_EQ(1,
196 metrics::NumSamples(video_prefix + "InputHeightInPixels"));
197 EXPECT_METRIC_EQ(1, metrics::NumSamples(video_prefix + "SentWidthInPixels"));
198 EXPECT_METRIC_EQ(1, metrics::NumSamples(video_prefix + "SentHeightInPixels"));
199 EXPECT_METRIC_EQ(1,
200 metrics::NumSamples(video_prefix + "ReceivedWidthInPixels"));
201 EXPECT_METRIC_EQ(
202 1, metrics::NumSamples(video_prefix + "ReceivedHeightInPixels"));
203
204 EXPECT_METRIC_EQ(1, metrics::NumEvents(video_prefix + "InputWidthInPixels",
205 kDefaultWidth));
206 EXPECT_METRIC_EQ(1, metrics::NumEvents(video_prefix + "InputHeightInPixels",
207 kDefaultHeight));
208 EXPECT_METRIC_EQ(
209 1, metrics::NumEvents(video_prefix + "SentWidthInPixels", kDefaultWidth));
210 EXPECT_METRIC_EQ(1, metrics::NumEvents(video_prefix + "SentHeightInPixels",
211 kDefaultHeight));
212 EXPECT_METRIC_EQ(1, metrics::NumEvents(video_prefix + "ReceivedWidthInPixels",
213 kDefaultWidth));
214 EXPECT_METRIC_EQ(1,
215 metrics::NumEvents(video_prefix + "ReceivedHeightInPixels",
216 kDefaultHeight));
217
218 EXPECT_METRIC_EQ(1,
219 metrics::NumSamples(video_prefix + "InputFramesPerSecond"));
220 EXPECT_METRIC_EQ(1,
221 metrics::NumSamples(video_prefix + "SentFramesPerSecond"));
222 EXPECT_METRIC_EQ(1,
223 metrics::NumSamples("WebRTC.Video.DecodedFramesPerSecond"));
224 EXPECT_METRIC_EQ(1,
225 metrics::NumSamples("WebRTC.Video.RenderFramesPerSecond"));
226 EXPECT_METRIC_EQ(1,
227 metrics::NumSamples("WebRTC.Video.DelayedFramesToRenderer"));
228
229 EXPECT_METRIC_EQ(1,
230 metrics::NumSamples("WebRTC.Video.JitterBufferDelayInMs"));
231 EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.TargetDelayInMs"));
232 EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.CurrentDelayInMs"));
233 EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.OnewayDelayInMs"));
234
235 EXPECT_METRIC_EQ(1, metrics::NumSamples(video_prefix + "EndToEndDelayInMs" +
236 video_suffix));
237 EXPECT_METRIC_EQ(1,
238 metrics::NumSamples(video_prefix + "EndToEndDelayMaxInMs" +
239 video_suffix));
240 EXPECT_METRIC_EQ(1, metrics::NumSamples(video_prefix + "InterframeDelayInMs" +
241 video_suffix));
242 EXPECT_METRIC_EQ(1,
243 metrics::NumSamples(video_prefix + "InterframeDelayMaxInMs" +
244 video_suffix));
245
246 EXPECT_METRIC_EQ(
247 1, metrics::NumSamples("WebRTC.Video.RenderSqrtPixelsPerSecond"));
248
249 EXPECT_METRIC_EQ(1, metrics::NumSamples(video_prefix + "EncodeTimeInMs"));
250 EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.DecodeTimeInMs"));
251
252 EXPECT_METRIC_EQ(1,
253 metrics::NumSamples(video_prefix + "NumberOfPauseEvents"));
254 EXPECT_METRIC_EQ(1,
255 metrics::NumSamples(video_prefix + "PausedTimeInPercent"));
256
257 EXPECT_METRIC_EQ(1, metrics::NumSamples(video_prefix + "BitrateSentInKbps"));
258 EXPECT_METRIC_EQ(1,
259 metrics::NumSamples("WebRTC.Video.BitrateReceivedInKbps"));
260 EXPECT_METRIC_EQ(
261 1, metrics::NumSamples(video_prefix + "MediaBitrateSentInKbps"));
262 EXPECT_METRIC_EQ(
263 1, metrics::NumSamples("WebRTC.Video.MediaBitrateReceivedInKbps"));
264 EXPECT_METRIC_EQ(
265 1, metrics::NumSamples(video_prefix + "PaddingBitrateSentInKbps"));
266 EXPECT_METRIC_EQ(
267 1, metrics::NumSamples("WebRTC.Video.PaddingBitrateReceivedInKbps"));
268 EXPECT_METRIC_EQ(
269 1, metrics::NumSamples(video_prefix + "RetransmittedBitrateSentInKbps"));
270 EXPECT_METRIC_EQ(1, metrics::NumSamples(
271 "WebRTC.Video.RetransmittedBitrateReceivedInKbps"));
272
273 EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.SendDelayInMs"));
274 EXPECT_METRIC_EQ(1, metrics::NumSamples(video_prefix + "SendSideDelayInMs"));
275 EXPECT_METRIC_EQ(1,
276 metrics::NumSamples(video_prefix + "SendSideDelayMaxInMs"));
277
278 int num_rtx_samples = use_rtx ? 1 : 0;
279 EXPECT_METRIC_EQ(num_rtx_samples,
280 metrics::NumSamples("WebRTC.Video.RtxBitrateSentInKbps"));
281 EXPECT_METRIC_EQ(
282 num_rtx_samples,
283 metrics::NumSamples("WebRTC.Video.RtxBitrateReceivedInKbps"));
284
285 int num_red_samples = use_fec ? 1 : 0;
286 EXPECT_METRIC_EQ(num_red_samples,
287 metrics::NumSamples("WebRTC.Video.FecBitrateSentInKbps"));
288 EXPECT_METRIC_EQ(
289 num_red_samples,
290 metrics::NumSamples("WebRTC.Video.FecBitrateReceivedInKbps"));
291 EXPECT_METRIC_EQ(
292 num_red_samples,
293 metrics::NumSamples("WebRTC.Video.ReceivedFecPacketsInPercent"));
294 }
295
TEST_F(HistogramTest,VerifyStatsWithRtx)296 TEST_F(HistogramTest, VerifyStatsWithRtx) {
297 const bool kEnabledRtx = true;
298 const bool kEnabledRed = false;
299 const bool kScreenshare = false;
300 VerifyHistogramStats(kEnabledRtx, kEnabledRed, kScreenshare);
301 }
302
TEST_F(HistogramTest,VerifyStatsWithRed)303 TEST_F(HistogramTest, VerifyStatsWithRed) {
304 const bool kEnabledRtx = false;
305 const bool kEnabledRed = true;
306 const bool kScreenshare = false;
307 VerifyHistogramStats(kEnabledRtx, kEnabledRed, kScreenshare);
308 }
309
TEST_F(HistogramTest,VerifyStatsWithScreenshare)310 TEST_F(HistogramTest, VerifyStatsWithScreenshare) {
311 const bool kEnabledRtx = false;
312 const bool kEnabledRed = false;
313 const bool kScreenshare = true;
314 VerifyHistogramStats(kEnabledRtx, kEnabledRed, kScreenshare);
315 }
316
317 } // namespace webrtc
318