1 // Copyright 2013 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/file_util.h" 7 #include "base/json/json_reader.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "base/path_service.h" 10 #include "base/process/launch.h" 11 #include "base/process/process_metrics.h" 12 #include "base/strings/string_split.h" 13 #include "base/strings/stringprintf.h" 14 #include "base/synchronization/waitable_event.h" 15 #include "base/test/test_timeouts.h" 16 #include "base/time/time.h" 17 #include "chrome/browser/browser_process.h" 18 #include "chrome/browser/media/webrtc_browsertest_base.h" 19 #include "chrome/browser/media/webrtc_browsertest_common.h" 20 #include "chrome/browser/media/webrtc_browsertest_perf.h" 21 #include "chrome/browser/ui/browser.h" 22 #include "chrome/browser/ui/browser_tabstrip.h" 23 #include "chrome/browser/ui/tabs/tab_strip_model.h" 24 #include "chrome/common/chrome_switches.h" 25 #include "chrome/test/base/in_process_browser_test.h" 26 #include "chrome/test/base/ui_test_utils.h" 27 #include "chrome/test/ui/ui_test.h" 28 #include "content/public/browser/notification_service.h" 29 #include "content/public/browser/render_process_host.h" 30 #include "content/public/test/browser_test_utils.h" 31 #include "media/base/media_switches.h" 32 #include "net/test/embedded_test_server/embedded_test_server.h" 33 #include "testing/perf/perf_test.h" 34 35 static const char kMainWebrtcTestHtmlPage[] = 36 "/webrtc/webrtc_jsep01_test.html"; 37 38 // Top-level integration test for WebRTC. Requires a real webcam and microphone 39 // on the running system. This test is not meant to run in the main browser 40 // test suite since normal tester machines do not have webcams. 41 class WebrtcBrowserTest : public WebRtcTestBase { 42 public: 43 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { 44 PeerConnectionServerRunner::KillAllPeerConnectionServersOnCurrentSystem(); 45 DetectErrorsInJavaScript(); // Look for errors in our rather complex js. 46 } 47 48 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 49 // This test expects real device handling and requires a real webcam / audio 50 // device; it will not work with fake devices. 51 EXPECT_FALSE(command_line->HasSwitch( 52 switches::kUseFakeDeviceForMediaStream)); 53 EXPECT_FALSE(command_line->HasSwitch( 54 switches::kUseFakeUIForMediaStream)); 55 56 // The video playback will not work without a GPU, so force its use here. 57 command_line->AppendSwitch(switches::kUseGpuInTests); 58 59 // Flag used by TestWebAudioMediaStream to force garbage collection. 60 command_line->AppendSwitchASCII(switches::kJavaScriptFlags, "--expose-gc"); 61 } 62 63 void EstablishCall(content::WebContents* from_tab, 64 content::WebContents* to_tab) { 65 ConnectToPeerConnectionServer("peer 1", from_tab); 66 ConnectToPeerConnectionServer("peer 2", to_tab); 67 68 EXPECT_EQ("ok-peerconnection-created", 69 ExecuteJavascript("preparePeerConnection()", from_tab)); 70 EXPECT_EQ("ok-added", 71 ExecuteJavascript("addLocalStream()", from_tab)); 72 EXPECT_EQ("ok-negotiating", 73 ExecuteJavascript("negotiateCall()", from_tab)); 74 75 // Ensure the call gets up on both sides. 76 EXPECT_TRUE(PollingWaitUntil("getPeerConnectionReadyState()", 77 "active", from_tab)); 78 EXPECT_TRUE(PollingWaitUntil("getPeerConnectionReadyState()", 79 "active", to_tab)); 80 } 81 82 void StartDetectingVideo(content::WebContents* tab_contents, 83 const std::string& video_element) { 84 std::string javascript = base::StringPrintf( 85 "startDetection('%s', 'frame-buffer', 320, 240)", 86 video_element.c_str()); 87 EXPECT_EQ("ok-started", ExecuteJavascript(javascript, tab_contents)); 88 } 89 90 void WaitForVideoToPlay(content::WebContents* tab_contents) { 91 EXPECT_TRUE(PollingWaitUntil("isVideoPlaying()", "video-playing", 92 tab_contents)); 93 } 94 95 void WaitForVideoToStopPlaying(content::WebContents* tab_contents) { 96 EXPECT_TRUE(PollingWaitUntil("isVideoPlaying()", "video-not-playing", 97 tab_contents)); 98 } 99 100 void HangUp(content::WebContents* from_tab) { 101 EXPECT_EQ("ok-call-hung-up", ExecuteJavascript("hangUp()", from_tab)); 102 } 103 104 void WaitUntilHangupVerified(content::WebContents* tab_contents) { 105 EXPECT_TRUE(PollingWaitUntil("getPeerConnectionReadyState()", 106 "no-peer-connection", tab_contents)); 107 } 108 109 std::string ToggleLocalVideoTrack(content::WebContents* tab_contents) { 110 // Toggle the only video track in the page (e.g. video track 0). 111 return ExecuteJavascript("toggleLocalStream(" 112 "function(local) { return local.getVideoTracks()[0]; }, " 113 "'video');", tab_contents); 114 } 115 116 std::string ToggleRemoteVideoTrack(content::WebContents* tab_contents) { 117 // Toggle the only video track in the page (e.g. video track 0). 118 return ExecuteJavascript("toggleRemoteStream(" 119 "function(local) { return local.getVideoTracks()[0]; }, " 120 "'video');", tab_contents); 121 } 122 123 void PrintProcessMetrics(base::ProcessMetrics* process_metrics, 124 const std::string& suffix) { 125 perf_test::PrintResult("cpu", "", "cpu" + suffix, 126 process_metrics->GetCPUUsage(), 127 "%", true); 128 perf_test::PrintResult("memory", "", "ws_peak" + suffix, 129 process_metrics->GetPeakWorkingSetSize(), 130 "bytes", true); 131 perf_test::PrintResult("memory", "", "ws_final" + suffix, 132 process_metrics->GetWorkingSetSize(), 133 "bytes", false); 134 135 size_t private_mem; 136 size_t shared_mem; 137 if (process_metrics->GetMemoryBytes(&private_mem, &shared_mem)) { 138 perf_test::PrintResult("memory", "", "private_mem_final" + suffix, 139 private_mem, "bytes", false); 140 perf_test::PrintResult("memory", "", "shared_mem_final" + suffix, 141 shared_mem, "bytes", false); 142 } 143 } 144 145 // Tries to extract data from peerConnectionDataStore in the webrtc-internals 146 // tab. The caller owns the parsed data. Returns NULL on failure. 147 base::DictionaryValue* GetWebrtcInternalsData( 148 content::WebContents* webrtc_internals_tab) { 149 std::string all_stats_json = ExecuteJavascript( 150 "window.domAutomationController.send(" 151 " JSON.stringify(peerConnectionDataStore));", 152 webrtc_internals_tab); 153 154 base::Value* parsed_json = base::JSONReader::Read(all_stats_json); 155 base::DictionaryValue* result; 156 if (parsed_json && parsed_json->GetAsDictionary(&result)) 157 return result; 158 159 return NULL; 160 } 161 162 const base::DictionaryValue* GetDataOnFirstPeerConnection( 163 const base::DictionaryValue* all_data) { 164 base::DictionaryValue::Iterator iterator(*all_data); 165 166 const base::DictionaryValue* result; 167 if (!iterator.IsAtEnd() && iterator.value().GetAsDictionary(&result)) 168 return result; 169 170 return NULL; 171 } 172 173 content::WebContents* OpenTestPageAndGetUserMediaInNewTab() { 174 return OpenPageAndGetUserMediaInNewTab( 175 embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage)); 176 } 177 178 PeerConnectionServerRunner peerconnection_server_; 179 }; 180 181 IN_PROC_BROWSER_TEST_F(WebrtcBrowserTest, 182 MANUAL_RunsAudioVideoWebRTCCallInTwoTabs) { 183 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 184 ASSERT_TRUE(peerconnection_server_.Start()); 185 186 content::WebContents* left_tab = OpenTestPageAndGetUserMediaInNewTab(); 187 content::WebContents* right_tab = OpenTestPageAndGetUserMediaInNewTab(); 188 189 EstablishCall(left_tab, right_tab); 190 191 StartDetectingVideo(left_tab, "remote-view"); 192 StartDetectingVideo(right_tab, "remote-view"); 193 194 WaitForVideoToPlay(left_tab); 195 WaitForVideoToPlay(right_tab); 196 197 HangUp(left_tab); 198 WaitUntilHangupVerified(left_tab); 199 WaitUntilHangupVerified(right_tab); 200 201 ASSERT_TRUE(peerconnection_server_.Stop()); 202 } 203 204 IN_PROC_BROWSER_TEST_F(WebrtcBrowserTest, MANUAL_CpuUsage15Seconds) { 205 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 206 ASSERT_TRUE(peerconnection_server_.Start()); 207 208 base::FilePath results_file; 209 ASSERT_TRUE(base::CreateTemporaryFile(&results_file)); 210 211 content::WebContents* left_tab = OpenTestPageAndGetUserMediaInNewTab(); 212 213 #if defined(OS_MACOSX) 214 // Don't measure renderer CPU on mac: requires a mach broker we don't have 215 // access to from the browser test. 216 scoped_ptr<base::ProcessMetrics> browser_process_metrics( 217 base::ProcessMetrics::CreateProcessMetrics( 218 base::Process::Current().handle(), NULL)); 219 browser_process_metrics->GetCPUUsage(); 220 #else 221 // Measure rendering CPU on platforms that support it. 222 base::ProcessHandle renderer_pid = 223 left_tab->GetRenderProcessHost()->GetHandle(); 224 scoped_ptr<base::ProcessMetrics> renderer_process_metrics( 225 base::ProcessMetrics::CreateProcessMetrics(renderer_pid)); 226 renderer_process_metrics->GetCPUUsage(); 227 228 scoped_ptr<base::ProcessMetrics> browser_process_metrics( 229 base::ProcessMetrics::CreateProcessMetrics( 230 base::Process::Current().handle())); 231 browser_process_metrics->GetCPUUsage(); 232 #endif 233 234 content::WebContents* right_tab = OpenTestPageAndGetUserMediaInNewTab(); 235 236 EstablishCall(left_tab, right_tab); 237 238 SleepInJavascript(left_tab, 15000); 239 240 HangUp(left_tab); 241 WaitUntilHangupVerified(left_tab); 242 WaitUntilHangupVerified(right_tab); 243 244 #if !defined(OS_MACOSX) 245 PrintProcessMetrics(renderer_process_metrics.get(), "_r"); 246 #endif 247 PrintProcessMetrics(browser_process_metrics.get(), "_b"); 248 249 ASSERT_TRUE(peerconnection_server_.Stop()); 250 } 251 252 IN_PROC_BROWSER_TEST_F(WebrtcBrowserTest, 253 MANUAL_TestMediaStreamTrackEnableDisable) { 254 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 255 ASSERT_TRUE(peerconnection_server_.Start()); 256 257 content::WebContents* left_tab = OpenTestPageAndGetUserMediaInNewTab(); 258 content::WebContents* right_tab = OpenTestPageAndGetUserMediaInNewTab(); 259 260 EstablishCall(left_tab, right_tab); 261 262 StartDetectingVideo(left_tab, "remote-view"); 263 StartDetectingVideo(right_tab, "remote-view"); 264 265 WaitForVideoToPlay(left_tab); 266 WaitForVideoToPlay(right_tab); 267 268 EXPECT_EQ("ok-video-toggled-to-false", ToggleLocalVideoTrack(left_tab)); 269 270 WaitForVideoToStopPlaying(right_tab); 271 272 EXPECT_EQ("ok-video-toggled-to-true", ToggleLocalVideoTrack(left_tab)); 273 274 WaitForVideoToPlay(right_tab); 275 276 HangUp(left_tab); 277 WaitUntilHangupVerified(left_tab); 278 WaitUntilHangupVerified(right_tab); 279 280 ASSERT_TRUE(peerconnection_server_.Stop()); 281 } 282 283 IN_PROC_BROWSER_TEST_F(WebrtcBrowserTest, 284 MANUAL_RunsAudioVideoCall60SecsAndLogsInternalMetrics) { 285 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 286 ASSERT_TRUE(peerconnection_server_.Start()); 287 288 ASSERT_GE(TestTimeouts::action_max_timeout().InSeconds(), 80) << 289 "This is a long-running test; you must specify " 290 "--ui-test-action-max-timeout to have a value of at least 80000."; 291 292 content::WebContents* left_tab = OpenTestPageAndGetUserMediaInNewTab(); 293 content::WebContents* right_tab = OpenTestPageAndGetUserMediaInNewTab(); 294 295 EstablishCall(left_tab, right_tab); 296 297 StartDetectingVideo(left_tab, "remote-view"); 298 StartDetectingVideo(right_tab, "remote-view"); 299 300 WaitForVideoToPlay(left_tab); 301 WaitForVideoToPlay(right_tab); 302 303 // Let values stabilize, bandwidth ramp up, etc. 304 SleepInJavascript(left_tab, 60000); 305 306 // Start measurements. 307 chrome::AddTabAt(browser(), GURL(), -1, true); 308 ui_test_utils::NavigateToURL(browser(), GURL("chrome://webrtc-internals")); 309 content::WebContents* webrtc_internals_tab = 310 browser()->tab_strip_model()->GetActiveWebContents(); 311 312 SleepInJavascript(left_tab, 10000); 313 314 scoped_ptr<base::DictionaryValue> all_data( 315 GetWebrtcInternalsData(webrtc_internals_tab)); 316 ASSERT_TRUE(all_data.get() != NULL); 317 318 const base::DictionaryValue* first_pc_dict = 319 GetDataOnFirstPeerConnection(all_data.get()); 320 ASSERT_TRUE(first_pc_dict != NULL); 321 PrintBweForVideoMetrics(*first_pc_dict); 322 PrintMetricsForAllStreams(*first_pc_dict); 323 324 HangUp(left_tab); 325 WaitUntilHangupVerified(left_tab); 326 WaitUntilHangupVerified(right_tab); 327 328 ASSERT_TRUE(peerconnection_server_.Stop()); 329 } 330 331 IN_PROC_BROWSER_TEST_F(WebrtcBrowserTest, TestWebAudioMediaStream) { 332 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 333 GURL url(embedded_test_server()->GetURL("/webrtc/webaudio_crash.html")); 334 ui_test_utils::NavigateToURL(browser(), url); 335 content::WebContents* tab = 336 browser()->tab_strip_model()->GetActiveWebContents(); 337 // A sleep is necessary to be able to detect the crash. 338 SleepInJavascript(tab, 1000); 339 340 ASSERT_FALSE(tab->IsCrashed()); 341 } 342