1 // Copyright (c) 2012 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/strings/string_number_conversions.h" 8 #include "base/strings/stringprintf.h" 9 #include "base/threading/platform_thread.h" 10 #include "base/values.h" 11 #include "content/browser/media/webrtc_internals.h" 12 #include "content/browser/web_contents/web_contents_impl.h" 13 #include "content/public/common/content_switches.h" 14 #include "content/public/test/browser_test_utils.h" 15 #include "content/public/test/content_browser_test_utils.h" 16 #include "content/public/test/test_utils.h" 17 #include "content/shell/browser/shell.h" 18 #include "content/test/webrtc_content_browsertest_base.h" 19 #include "media/audio/audio_manager.h" 20 #include "media/base/media_switches.h" 21 #include "net/test/embedded_test_server/embedded_test_server.h" 22 23 #if defined(OS_WIN) 24 #include "base/win/windows_version.h" 25 #endif 26 27 #if defined (OS_ANDROID) || defined(THREAD_SANITIZER) 28 // Just do the bare minimum of audio checking on Android and under TSAN since 29 // it's a bit sensitive to device performance. 30 static const char kUseLenientAudioChecking[] = "true"; 31 #else 32 static const char kUseLenientAudioChecking[] = "false"; 33 #endif 34 35 namespace content { 36 37 class WebRtcBrowserTest : public WebRtcContentBrowserTest, 38 public testing::WithParamInterface<bool> { 39 public: 40 WebRtcBrowserTest() {} 41 virtual ~WebRtcBrowserTest() {} 42 43 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 44 WebRtcContentBrowserTest::SetUpCommandLine(command_line); 45 46 bool enable_audio_track_processing = GetParam(); 47 if (!enable_audio_track_processing) 48 command_line->AppendSwitch(switches::kDisableAudioTrackProcessing); 49 } 50 51 // Convenience function since most peerconnection-call.html tests just load 52 // the page, kick off some javascript and wait for the title to change to OK. 53 void MakeTypicalPeerConnectionCall(const std::string& javascript) { 54 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 55 56 GURL url(embedded_test_server()->GetURL("/media/peerconnection-call.html")); 57 NavigateToURL(shell(), url); 58 59 DisableOpusIfOnAndroid(); 60 ExecuteJavascriptAndWaitForOk(javascript); 61 } 62 63 // Convenience method for making calls that detect if audio os playing (which 64 // has some special prerequisites, such that there needs to be an audio output 65 // device on the executing machine). 66 void MakeAudioDetectingPeerConnectionCall(const std::string& javascript) { 67 if (!media::AudioManager::Get()->HasAudioOutputDevices()) { 68 // Bots with no output devices will force the audio code into a state 69 // where it doesn't manage to set either the low or high latency path. 70 // This test will compute useless values in that case, so skip running on 71 // such bots (see crbug.com/326338). 72 LOG(INFO) << "Missing output devices: skipping test..."; 73 return; 74 } 75 76 ASSERT_TRUE(CommandLine::ForCurrentProcess()->HasSwitch( 77 switches::kUseFakeDeviceForMediaStream)) 78 << "Must run with fake devices since the test will explicitly look " 79 << "for the fake device signal."; 80 81 MakeTypicalPeerConnectionCall(javascript); 82 } 83 84 void DisableOpusIfOnAndroid() { 85 #if defined(OS_ANDROID) 86 // Always force iSAC 16K on Android for now (Opus is broken). 87 EXPECT_EQ("isac-forced", 88 ExecuteJavascriptAndReturnResult("forceIsac16KInSdp();")); 89 #endif 90 } 91 }; 92 93 static const bool kRunTestsWithFlag[] = { false, true }; 94 INSTANTIATE_TEST_CASE_P(WebRtcBrowserTests, 95 WebRtcBrowserTest, 96 testing::ValuesIn(kRunTestsWithFlag)); 97 98 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY) 99 // Timing out on ARM linux bot: http://crbug.com/238490 100 #define MAYBE_CanSetupDefaultVideoCall DISABLED_CanSetupDefaultVideoCall 101 #else 102 #define MAYBE_CanSetupDefaultVideoCall CanSetupDefaultVideoCall 103 #endif 104 105 // These tests will make a complete PeerConnection-based call and verify that 106 // video is playing for the call. 107 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, MAYBE_CanSetupDefaultVideoCall) { 108 MakeTypicalPeerConnectionCall( 109 "callAndExpectResolution({video: true}, 640, 480);"); 110 } 111 112 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, CanSetupVideoCallWith1To1AspecRatio) { 113 const std::string javascript = 114 "callAndExpectResolution({video: {mandatory: {minWidth: 320," 115 " maxWidth: 320, minHeight: 320, maxHeight: 320}}}, 320, 320);"; 116 MakeTypicalPeerConnectionCall(javascript); 117 } 118 119 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, 120 CanSetupVideoCallWith16To9AspecRatio) { 121 const std::string javascript = 122 "callAndExpectResolution({video: {mandatory: {minWidth: 640," 123 " maxWidth: 640, minAspectRatio: 1.777}}}, 640, 360);"; 124 MakeTypicalPeerConnectionCall(javascript); 125 } 126 127 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, 128 CanSetupVideoCallWith4To3AspecRatio) { 129 const std::string javascript = 130 "callAndExpectResolution({video: {mandatory: {minWidth: 960," 131 "maxAspectRatio: 1.333}}}, 960, 720);"; 132 MakeTypicalPeerConnectionCall(javascript); 133 } 134 135 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY) 136 // Timing out on ARM linux, see http://crbug.com/240376 137 #define MAYBE_CanSetupAudioAndVideoCall DISABLED_CanSetupAudioAndVideoCall 138 #else 139 #define MAYBE_CanSetupAudioAndVideoCall CanSetupAudioAndVideoCall 140 #endif 141 142 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, MAYBE_CanSetupAudioAndVideoCall) { 143 MakeTypicalPeerConnectionCall("call({video: true, audio: true});"); 144 } 145 146 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, MANUAL_CanSetupCallAndSendDtmf) { 147 MakeTypicalPeerConnectionCall("callAndSendDtmf(\'123,abc\');"); 148 } 149 150 // TODO(phoglund): this test fails because the peer connection state will be 151 // stable in the second negotiation round rather than have-local-offer. 152 // http://crbug.com/293125. 153 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, 154 DISABLED_CanMakeEmptyCallThenAddStreamsAndRenegotiate) { 155 const char* kJavascript = 156 "callEmptyThenAddOneStreamAndRenegotiate({video: true, audio: true});"; 157 MakeTypicalPeerConnectionCall(kJavascript); 158 } 159 160 // Below 2 test will make a complete PeerConnection-based call between pc1 and 161 // pc2, and then use the remote stream to setup a call between pc3 and pc4, and 162 // then verify that video is received on pc3 and pc4. 163 // The stream sent from pc3 to pc4 is the stream received on pc1. 164 // The stream sent from pc4 to pc3 is cloned from stream the stream received 165 // on pc2. 166 // Flaky on win xp. http://crbug.com/304775 167 #if defined(OS_WIN) 168 #define MAYBE_CanForwardRemoteStream DISABLED_CanForwardRemoteStream 169 #define MAYBE_CanForwardRemoteStream720p DISABLED_CanForwardRemoteStream720p 170 #else 171 #define MAYBE_CanForwardRemoteStream CanForwardRemoteStream 172 // Flaky on TSAN v2. http://crbug.com/373637 173 #if defined(THREAD_SANITIZER) 174 #define MAYBE_CanForwardRemoteStream720p DISABLED_CanForwardRemoteStream720p 175 #else 176 #define MAYBE_CanForwardRemoteStream720p CanForwardRemoteStream720p 177 #endif 178 #endif 179 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, MAYBE_CanForwardRemoteStream) { 180 #if defined (OS_ANDROID) 181 // This test fails on Nexus 5 devices. 182 // TODO(henrika): see http://crbug.com/362437 and http://crbug.com/359389 183 // for details. 184 CommandLine::ForCurrentProcess()->AppendSwitch( 185 switches::kDisableWebRtcHWDecoding); 186 #endif 187 MakeTypicalPeerConnectionCall( 188 "callAndForwardRemoteStream({video: true, audio: false});"); 189 } 190 191 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, MAYBE_CanForwardRemoteStream720p) { 192 #if defined (OS_ANDROID) 193 // This test fails on Nexus 5 devices. 194 // TODO(henrika): see http://crbug.com/362437 and http://crbug.com/359389 195 // for details. 196 CommandLine::ForCurrentProcess()->AppendSwitch( 197 switches::kDisableWebRtcHWDecoding); 198 #endif 199 const std::string javascript = GenerateGetUserMediaCall( 200 "callAndForwardRemoteStream", 1280, 1280, 720, 720, 10, 30); 201 MakeTypicalPeerConnectionCall(javascript); 202 } 203 204 // This test will make a complete PeerConnection-based call but remove the 205 // MSID and bundle attribute from the initial offer to verify that 206 // video is playing for the call even if the initiating client don't support 207 // MSID. http://tools.ietf.org/html/draft-alvestrand-rtcweb-msid-02 208 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY) 209 // Timing out on ARM linux, see http://crbug.com/240373 210 #define MAYBE_CanSetupAudioAndVideoCallWithoutMsidAndBundle\ 211 DISABLED_CanSetupAudioAndVideoCallWithoutMsidAndBundle 212 #else 213 #define MAYBE_CanSetupAudioAndVideoCallWithoutMsidAndBundle\ 214 CanSetupAudioAndVideoCallWithoutMsidAndBundle 215 #endif 216 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, 217 MAYBE_CanSetupAudioAndVideoCallWithoutMsidAndBundle) { 218 MakeTypicalPeerConnectionCall("callWithoutMsidAndBundle();"); 219 } 220 221 // This test will modify the SDP offer to an unsupported codec, which should 222 // cause SetLocalDescription to fail. 223 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, NegotiateUnsupportedVideoCodec) { 224 MakeTypicalPeerConnectionCall("negotiateUnsupportedVideoCodec();"); 225 } 226 227 // This test will modify the SDP offer to use no encryption, which should 228 // cause SetLocalDescription to fail. 229 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, NegotiateNonCryptoCall) { 230 MakeTypicalPeerConnectionCall("negotiateNonCryptoCall();"); 231 } 232 233 // This test can negotiate an SDP offer that includes a b=AS:xx to control 234 // the bandwidth for audio and video 235 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, NegotiateOfferWithBLine) { 236 MakeTypicalPeerConnectionCall("negotiateOfferWithBLine();"); 237 } 238 239 // This test will make a complete PeerConnection-based call using legacy SDP 240 // settings: GIce, external SDES, and no BUNDLE. 241 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY) 242 // Timing out on ARM linux, see http://crbug.com/240373 243 #define MAYBE_CanSetupLegacyCall DISABLED_CanSetupLegacyCall 244 #else 245 #define MAYBE_CanSetupLegacyCall CanSetupLegacyCall 246 #endif 247 248 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, MAYBE_CanSetupLegacyCall) { 249 MakeTypicalPeerConnectionCall("callWithLegacySdp();"); 250 } 251 252 // This test will make a PeerConnection-based call and test an unreliable text 253 // dataChannel. 254 // TODO(mallinath) - Remove this test after rtp based data channel is disabled. 255 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, CallWithDataOnly) { 256 MakeTypicalPeerConnectionCall("callWithDataOnly();"); 257 } 258 259 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, CallWithSctpDataOnly) { 260 MakeTypicalPeerConnectionCall("callWithSctpDataOnly();"); 261 } 262 263 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY) 264 // Timing out on ARM linux bot: http://crbug.com/238490 265 #define MAYBE_CallWithDataAndMedia DISABLED_CallWithDataAndMedia 266 #else 267 #define MAYBE_CallWithDataAndMedia CallWithDataAndMedia 268 #endif 269 270 // This test will make a PeerConnection-based call and test an unreliable text 271 // dataChannel and audio and video tracks. 272 // TODO(mallinath) - Remove this test after rtp based data channel is disabled. 273 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, DISABLED_CallWithDataAndMedia) { 274 MakeTypicalPeerConnectionCall("callWithDataAndMedia();"); 275 } 276 277 278 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY) 279 // Timing out on ARM linux bot: http://crbug.com/238490 280 #define MAYBE_CallWithSctpDataAndMedia DISABLED_CallWithSctpDataAndMedia 281 #else 282 #define MAYBE_CallWithSctpDataAndMedia CallWithSctpDataAndMedia 283 #endif 284 285 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, 286 MAYBE_CallWithSctpDataAndMedia) { 287 MakeTypicalPeerConnectionCall("callWithSctpDataAndMedia();"); 288 } 289 290 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY) 291 // Timing out on ARM linux bot: http://crbug.com/238490 292 #define MAYBE_CallWithDataAndLaterAddMedia DISABLED_CallWithDataAndLaterAddMedia 293 #else 294 // Temporarily disable the test on all platforms. http://crbug.com/293252 295 #define MAYBE_CallWithDataAndLaterAddMedia DISABLED_CallWithDataAndLaterAddMedia 296 #endif 297 298 // This test will make a PeerConnection-based call and test an unreliable text 299 // dataChannel and later add an audio and video track. 300 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, MAYBE_CallWithDataAndLaterAddMedia) { 301 MakeTypicalPeerConnectionCall("callWithDataAndLaterAddMedia();"); 302 } 303 304 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY) 305 // Timing out on ARM linux bot: http://crbug.com/238490 306 #define MAYBE_CallWithNewVideoMediaStream DISABLED_CallWithNewVideoMediaStream 307 #else 308 #define MAYBE_CallWithNewVideoMediaStream CallWithNewVideoMediaStream 309 #endif 310 311 // This test will make a PeerConnection-based call and send a new Video 312 // MediaStream that has been created based on a MediaStream created with 313 // getUserMedia. 314 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, MAYBE_CallWithNewVideoMediaStream) { 315 MakeTypicalPeerConnectionCall("callWithNewVideoMediaStream();"); 316 } 317 318 // This test will make a PeerConnection-based call and send a new Video 319 // MediaStream that has been created based on a MediaStream created with 320 // getUserMedia. When video is flowing, the VideoTrack is removed and an 321 // AudioTrack is added instead. 322 // TODO(phoglund): This test is manual since not all buildbots has an audio 323 // input. 324 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, MANUAL_CallAndModifyStream) { 325 MakeTypicalPeerConnectionCall( 326 "callWithNewVideoMediaStreamLaterSwitchToAudio();"); 327 } 328 329 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, AddTwoMediaStreamsToOnePC) { 330 MakeTypicalPeerConnectionCall("addTwoMediaStreamsToOneConnection();"); 331 } 332 333 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, 334 EstablishAudioVideoCallAndEnsureAudioIsPlaying) { 335 MakeAudioDetectingPeerConnectionCall(base::StringPrintf( 336 "callAndEnsureAudioIsPlaying(%s, {audio:true, video:true});", 337 kUseLenientAudioChecking)); 338 } 339 340 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, 341 EstablishAudioOnlyCallAndEnsureAudioIsPlaying) { 342 MakeAudioDetectingPeerConnectionCall(base::StringPrintf( 343 "callAndEnsureAudioIsPlaying(%s, {audio:true});", 344 kUseLenientAudioChecking)); 345 } 346 347 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, 348 EstablishAudioVideoCallAndVerifyMutingWorks) { 349 MakeAudioDetectingPeerConnectionCall(base::StringPrintf( 350 "callAndEnsureAudioTrackMutingWorks(%s);", kUseLenientAudioChecking)); 351 } 352 353 // Flaky on TSAN v2: http://crbug.com/373637 354 #if defined(THREAD_SANITIZER) 355 #define MAYBE_EstablishAudioVideoCallAndVerifyUnmutingWorks\ 356 DISABLED_EstablishAudioVideoCallAndVerifyUnmutingWorks 357 #else 358 #define MAYBE_EstablishAudioVideoCallAndVerifyUnmutingWorks\ 359 EstablishAudioVideoCallAndVerifyUnmutingWorks 360 #endif 361 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, 362 MAYBE_EstablishAudioVideoCallAndVerifyUnmutingWorks) { 363 MakeAudioDetectingPeerConnectionCall(base::StringPrintf( 364 "callAndEnsureAudioTrackUnmutingWorks(%s);", kUseLenientAudioChecking)); 365 } 366 367 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, CallAndVerifyVideoMutingWorks) { 368 MakeTypicalPeerConnectionCall("callAndEnsureVideoTrackMutingWorks();"); 369 } 370 371 #if defined(OS_WIN) 372 #define IntToStringType base::IntToString16 373 #else 374 #define IntToStringType base::IntToString 375 #endif 376 377 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY) 378 // Timing out on ARM linux bot: http://crbug.com/238490 379 #define MAYBE_CallWithAecDump DISABLED_CallWithAecDump 380 #else 381 #define MAYBE_CallWithAecDump CallWithAecDump 382 #endif 383 384 // This tests will make a complete PeerConnection-based call, verify that 385 // video is playing for the call, and verify that a non-empty AEC dump file 386 // exists. The AEC dump is enabled through webrtc-internals. The HTML and 387 // Javascript is bypassed since it would trigger a file picker dialog. Instead, 388 // the dialog callback FileSelected() is invoked directly. In fact, there's 389 // never a webrtc-internals page opened at all since that's not needed. 390 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, MAYBE_CallWithAecDump) { 391 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 392 393 // We must navigate somewhere first so that the render process is created. 394 NavigateToURL(shell(), GURL("")); 395 396 base::FilePath dump_file; 397 ASSERT_TRUE(CreateTemporaryFile(&dump_file)); 398 399 // This fakes the behavior of another open tab with webrtc-internals, and 400 // enabling AEC dump in that tab. 401 WebRTCInternals::GetInstance()->FileSelected(dump_file, -1, NULL); 402 403 GURL url(embedded_test_server()->GetURL("/media/peerconnection-call.html")); 404 NavigateToURL(shell(), url); 405 DisableOpusIfOnAndroid(); 406 ExecuteJavascriptAndWaitForOk("call({video: true, audio: true});"); 407 408 // Get the ID for the render process host. There should only be one. 409 RenderProcessHost::iterator it( 410 content::RenderProcessHost::AllHostsIterator()); 411 int render_process_host_id = it.GetCurrentValue()->GetID(); 412 EXPECT_GE(render_process_host_id, 0); 413 414 // Add file extensions that we expect to be added. 415 static const int kExpectedConsumerId = 0; 416 dump_file = dump_file.AddExtension(IntToStringType(render_process_host_id)) 417 .AddExtension(IntToStringType(kExpectedConsumerId)); 418 419 EXPECT_TRUE(base::PathExists(dump_file)); 420 int64 file_size = 0; 421 EXPECT_TRUE(base::GetFileSize(dump_file, &file_size)); 422 EXPECT_GT(file_size, 0); 423 424 base::DeleteFile(dump_file, false); 425 } 426 427 // TODO(grunell): Add test for multiple dumps when re-use of 428 // MediaStreamAudioProcessor in AudioCapturer has been removed. 429 430 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY) 431 // Timing out on ARM linux bot: http://crbug.com/238490 432 #define MAYBE_CallWithAecDumpEnabledThenDisabled DISABLED_CallWithAecDumpEnabledThenDisabled 433 #else 434 #define MAYBE_CallWithAecDumpEnabledThenDisabled CallWithAecDumpEnabledThenDisabled 435 #endif 436 437 // As above, but enable and disable dump before starting a call. The file should 438 // be created, but should be empty. 439 IN_PROC_BROWSER_TEST_P(WebRtcBrowserTest, 440 MAYBE_CallWithAecDumpEnabledThenDisabled) { 441 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 442 443 // We must navigate somewhere first so that the render process is created. 444 NavigateToURL(shell(), GURL("")); 445 446 base::FilePath dump_file; 447 ASSERT_TRUE(CreateTemporaryFile(&dump_file)); 448 449 // This fakes the behavior of another open tab with webrtc-internals, and 450 // enabling AEC dump in that tab, then disabling it. 451 WebRTCInternals::GetInstance()->FileSelected(dump_file, -1, NULL); 452 WebRTCInternals::GetInstance()->DisableAecDump(); 453 454 GURL url(embedded_test_server()->GetURL("/media/peerconnection-call.html")); 455 NavigateToURL(shell(), url); 456 DisableOpusIfOnAndroid(); 457 ExecuteJavascriptAndWaitForOk("call({video: true, audio: true});"); 458 459 EXPECT_TRUE(base::PathExists(dump_file)); 460 int64 file_size = 0; 461 EXPECT_TRUE(base::GetFileSize(dump_file, &file_size)); 462 EXPECT_EQ(0, file_size); 463 464 base::DeleteFile(dump_file, false); 465 } 466 467 } // namespace content 468