1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/command_line.h"
6 #include "base/strings/stringprintf.h"
7 #include "base/test/test_timeouts.h"
8 #include "base/time/time.h"
9 #include "chrome/browser/media/webrtc/test_stats_dictionary.h"
10 #include "chrome/browser/media/webrtc/webrtc_browsertest_base.h"
11 #include "chrome/browser/media/webrtc/webrtc_browsertest_common.h"
12 #include "content/public/browser/web_contents.h"
13 #include "content/public/common/content_switches.h"
14 #include "content/public/test/browser_test.h"
15 #include "media/base/media_switches.h"
16 #include "testing/perf/perf_test.h"
17 #include "ui/gl/gl_switches.h"
18 
19 namespace {
20 
21 static const char kMainWebrtcTestHtmlPage[] =
22     "/webrtc/webrtc_video_display_perf_test.html";
23 static const char kInboundRtp[] = "inbound-rtp";
24 static const char kOutboundRtp[] = "outbound-rtp";
25 
26 // Sums up "RTC[In/Out]boundRTPStreamStats.bytes_[received/sent]" values.
GetTotalRTPStreamBytes(content::TestStatsReportDictionary * report,const char * type,const char * media_type)27 double GetTotalRTPStreamBytes(content::TestStatsReportDictionary* report,
28                               const char* type,
29                               const char* media_type) {
30   DCHECK(type == kInboundRtp || type == kOutboundRtp);
31   const char* bytes_name =
32       (type == kInboundRtp) ? "bytesReceived" : "bytesSent";
33   double total_bytes = 0.0;
34   report->ForEach([&type, &bytes_name, &media_type,
35                    &total_bytes](const content::TestStatsDictionary& stats) {
36     if (stats.GetString("type") == type &&
37         stats.GetString("mediaType") == media_type) {
38       total_bytes += stats.GetNumber(bytes_name);
39     }
40   });
41   return total_bytes;
42 }
43 
GetVideoBytesSent(content::TestStatsReportDictionary * report)44 double GetVideoBytesSent(content::TestStatsReportDictionary* report) {
45   return GetTotalRTPStreamBytes(report, kOutboundRtp, "video");
46 }
47 
GetVideoBytesReceived(content::TestStatsReportDictionary * report)48 double GetVideoBytesReceived(content::TestStatsReportDictionary* report) {
49   return GetTotalRTPStreamBytes(report, kInboundRtp, "video");
50 }
51 
52 }  // anonymous namespace
53 
54 namespace content {
55 
56 // Tests the performance of WebRTC peer connection with high bitrate
57 //
58 // This test creates a WebRTC peer connection between two tabs and sets a very
59 // high target bitrate to observe any perf regressions/improvements for such
60 // cases. In order to achieve this, we use a fake codec that creates a dummy
61 // output for the given bitrate.
62 class WebRtcVideoHighBitrateBrowserTest : public WebRtcTestBase {
63  public:
SetUpInProcessBrowserTestFixture()64   void SetUpInProcessBrowserTestFixture() override {
65     DetectErrorsInJavaScript();
66   }
67 
SetUpCommandLine(base::CommandLine * command_line)68   void SetUpCommandLine(base::CommandLine* command_line) override {
69     command_line->AppendSwitch(switches::kUseFakeCodecForPeerConnection);
70     command_line->AppendSwitch(switches::kUseFakeUIForMediaStream);
71     command_line->AppendSwitch(switches::kUseGpuInTests);
72   }
73 
74  protected:
SetDefaultVideoTargetBitrate(content::WebContents * tab,int bits_per_second)75   void SetDefaultVideoTargetBitrate(content::WebContents* tab,
76                                     int bits_per_second) {
77     EXPECT_EQ("ok", ExecuteJavascript(
78                         base::StringPrintf("setDefaultVideoTargetBitrate(%d)",
79                                            bits_per_second),
80                         tab));
81   }
82 };
83 
IN_PROC_BROWSER_TEST_F(WebRtcVideoHighBitrateBrowserTest,MANUAL_HighBitrateEncodeDecode)84 IN_PROC_BROWSER_TEST_F(WebRtcVideoHighBitrateBrowserTest,
85                        MANUAL_HighBitrateEncodeDecode) {
86   ASSERT_TRUE(embedded_test_server()->Start());
87   ASSERT_GE(TestTimeouts::test_launcher_timeout().InSeconds(), 30)
88       << "This is a long-running test; you must specify "
89          "--test-launcher-timeout to have a value of at least 30000.";
90   ASSERT_GE(TestTimeouts::action_max_timeout().InSeconds(), 30)
91       << "This is a long-running test; you must specify "
92          "--ui-test-action-max-timeout to have a value of at least 30000.";
93   ASSERT_LT(TestTimeouts::action_max_timeout(),
94             TestTimeouts::test_launcher_timeout())
95       << "action_max_timeout needs to be strictly-less-than "
96          "test_launcher_timeout";
97 
98   content::WebContents* left_tab =
99       OpenPageAndGetUserMediaInNewTabWithConstraints(
100           embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage),
101           "{audio: true, video: true}");
102   content::WebContents* right_tab =
103       OpenPageAndGetUserMediaInNewTabWithConstraints(
104           embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage),
105           "{audio: true, video: false}");
106   SetupPeerconnectionWithLocalStream(left_tab);
107   SetupPeerconnectionWithLocalStream(right_tab);
108   const int target_bits_per_second = 80000;
109   SetDefaultVideoTargetBitrate(left_tab, target_bits_per_second);
110   SetDefaultVideoTargetBitrate(right_tab, target_bits_per_second);
111   NegotiateCall(left_tab, right_tab);
112 
113   // Run the connection a bit to ramp up.
114   test::SleepInJavascript(left_tab, 10000);
115 
116   scoped_refptr<TestStatsReportDictionary> sender_report =
117       GetStatsReportDictionary(left_tab);
118   const double video_bytes_sent_before = GetVideoBytesSent(sender_report.get());
119   scoped_refptr<TestStatsReportDictionary> receiver_report =
120       GetStatsReportDictionary(right_tab);
121   const double video_bytes_received_before =
122       GetVideoBytesReceived(receiver_report.get());
123 
124   // Collect stats.
125   const double duration_in_seconds = 5.0;
126   test::SleepInJavascript(
127       left_tab, duration_in_seconds * base::Time::kMillisecondsPerSecond);
128 
129   sender_report = GetStatsReportDictionary(left_tab);
130   const double video_bytes_sent_after = GetVideoBytesSent(sender_report.get());
131   receiver_report = GetStatsReportDictionary(right_tab);
132   const double video_bytes_received_after =
133       GetVideoBytesReceived(receiver_report.get());
134 
135   const double video_send_rate =
136       (video_bytes_sent_after - video_bytes_sent_before) / duration_in_seconds;
137   const double video_receive_rate =
138       (video_bytes_received_after - video_bytes_received_before) /
139       duration_in_seconds;
140 
141   perf_test::PrintResult("video", "", "send_rate", video_send_rate,
142                          "bytes/second", false);
143   perf_test::PrintResult("video", "", "receive_rate", video_receive_rate,
144                          "bytes/second", false);
145 
146   HangUp(left_tab);
147   HangUp(right_tab);
148 }
149 
150 }  // namespace content
151