1 // Copyright (c) 2014 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/process/process_handle.h" 6 #include "base/strings/string_number_conversions.h" 7 #include "base/strings/stringprintf.h" 8 #include "content/browser/media/webrtc_internals.h" 9 #include "content/browser/web_contents/web_contents_impl.h" 10 #include "content/public/test/browser_test_utils.h" 11 #include "content/public/test/content_browser_test_utils.h" 12 #include "content/shell/browser/shell.h" 13 #include "content/test/webrtc_content_browsertest_base.h" 14 #include "media/audio/audio_manager.h" 15 #include "net/test/embedded_test_server/embedded_test_server.h" 16 17 namespace { 18 19 const int kExpectedConsumerId = 0; 20 21 // Get the ID for the render process host when there should only be one. 22 bool GetRenderProcessHostId(base::ProcessId* id) { 23 content::RenderProcessHost::iterator it( 24 content::RenderProcessHost::AllHostsIterator()); 25 *id = base::GetProcId(it.GetCurrentValue()->GetHandle()); 26 EXPECT_NE(base::kNullProcessId, *id); 27 if (*id == base::kNullProcessId) 28 return false; 29 it.Advance(); 30 EXPECT_TRUE(it.IsAtEnd()); 31 return it.IsAtEnd(); 32 } 33 34 } // namespace 35 36 namespace content { 37 38 class WebRtcAecDumpBrowserTest : public WebRtcContentBrowserTest { 39 public: 40 WebRtcAecDumpBrowserTest() {} 41 virtual ~WebRtcAecDumpBrowserTest() {} 42 }; 43 44 #if defined(OS_WIN) 45 #define IntToStringType base::IntToString16 46 #else 47 #define IntToStringType base::IntToString 48 #endif 49 50 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY) 51 // Timing out on ARM linux bot: http://crbug.com/238490 52 #define MAYBE_CallWithAecDump DISABLED_CallWithAecDump 53 #elif defined(OS_ANDROID) && defined(ADDRESS_SANITIZER) 54 // Renderer crashes under Android ASAN: https://crbug.com/408496. 55 #define MAYBE_CallWithAecDump DISABLED_CallWithAecDump 56 #elif defined(OS_WIN) && !defined(NDEBUG) 57 // Flaky on Webkit Win7 Debug bot: http://crbug.com/417756 58 #define MAYBE_CallWithAecDump DISABLED_CallWithAecDump 59 #else 60 #define MAYBE_CallWithAecDump CallWithAecDump 61 #endif 62 63 // This tests will make a complete PeerConnection-based call, verify that 64 // video is playing for the call, and verify that a non-empty AEC dump file 65 // exists. The AEC dump is enabled through webrtc-internals. The HTML and 66 // Javascript is bypassed since it would trigger a file picker dialog. Instead, 67 // the dialog callback FileSelected() is invoked directly. In fact, there's 68 // never a webrtc-internals page opened at all since that's not needed. 69 IN_PROC_BROWSER_TEST_F(WebRtcAecDumpBrowserTest, MAYBE_CallWithAecDump) { 70 if (!media::AudioManager::Get()->HasAudioOutputDevices()) { 71 LOG(INFO) << "Missing output devices: skipping test..."; 72 return; 73 } 74 75 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 76 77 // We must navigate somewhere first so that the render process is created. 78 NavigateToURL(shell(), GURL("")); 79 80 base::FilePath dump_file; 81 ASSERT_TRUE(CreateTemporaryFile(&dump_file)); 82 base::DeleteFile(dump_file, false); 83 84 // This fakes the behavior of another open tab with webrtc-internals, and 85 // enabling AEC dump in that tab. 86 WebRTCInternals::GetInstance()->FileSelected(dump_file, -1, NULL); 87 88 GURL url(embedded_test_server()->GetURL("/media/peerconnection-call.html")); 89 NavigateToURL(shell(), url); 90 DisableOpusIfOnAndroid(); 91 ExecuteJavascriptAndWaitForOk("call({video: true, audio: true});"); 92 93 EXPECT_FALSE(base::PathExists(dump_file)); 94 95 // Add file extensions that we expect to be added. The dump name will be 96 // <temporary path>.<render process id>.<consumer id>, for example 97 // "/tmp/.com.google.Chrome.Z6UC3P.12345.0". 98 base::ProcessId render_process_id = base::kNullProcessId; 99 EXPECT_TRUE(GetRenderProcessHostId(&render_process_id)); 100 dump_file = dump_file.AddExtension(IntToStringType(render_process_id)) 101 .AddExtension(IntToStringType(kExpectedConsumerId)); 102 103 EXPECT_TRUE(base::PathExists(dump_file)); 104 int64 file_size = 0; 105 EXPECT_TRUE(base::GetFileSize(dump_file, &file_size)); 106 EXPECT_GT(file_size, 0); 107 108 base::DeleteFile(dump_file, false); 109 } 110 111 // TODO(grunell): Add test for multiple dumps when re-use of 112 // MediaStreamAudioProcessor in AudioCapturer has been removed. 113 114 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY) 115 // Timing out on ARM linux bot: http://crbug.com/238490 116 #define MAYBE_CallWithAecDumpEnabledThenDisabled DISABLED_CallWithAecDumpEnabledThenDisabled 117 #elif defined(OS_ANDROID) && defined(ADDRESS_SANITIZER) 118 // Renderer crashes under Android ASAN: https://crbug.com/408496. 119 #define MAYBE_CallWithAecDumpEnabledThenDisabled DISABLED_CallWithAecDumpEnabledThenDisabled 120 #else 121 #define MAYBE_CallWithAecDumpEnabledThenDisabled CallWithAecDumpEnabledThenDisabled 122 #endif 123 124 // As above, but enable and disable dump before starting a call. The file should 125 // be created, but should be empty. 126 IN_PROC_BROWSER_TEST_F(WebRtcAecDumpBrowserTest, 127 MAYBE_CallWithAecDumpEnabledThenDisabled) { 128 if (!media::AudioManager::Get()->HasAudioOutputDevices()) { 129 LOG(INFO) << "Missing output devices: skipping test..."; 130 return; 131 } 132 133 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 134 135 // We must navigate somewhere first so that the render process is created. 136 NavigateToURL(shell(), GURL("")); 137 138 base::FilePath dump_file; 139 ASSERT_TRUE(CreateTemporaryFile(&dump_file)); 140 base::DeleteFile(dump_file, false); 141 142 // This fakes the behavior of another open tab with webrtc-internals, and 143 // enabling AEC dump in that tab, then disabling it. 144 WebRTCInternals::GetInstance()->FileSelected(dump_file, -1, NULL); 145 WebRTCInternals::GetInstance()->DisableAecDump(); 146 147 GURL url(embedded_test_server()->GetURL("/media/peerconnection-call.html")); 148 NavigateToURL(shell(), url); 149 DisableOpusIfOnAndroid(); 150 ExecuteJavascriptAndWaitForOk("call({video: true, audio: true});"); 151 152 // Add file extensions that we expect to be added. 153 base::ProcessId render_process_id = base::kNullProcessId; 154 EXPECT_TRUE(GetRenderProcessHostId(&render_process_id)); 155 dump_file = dump_file.AddExtension(IntToStringType(render_process_id)) 156 .AddExtension(IntToStringType(kExpectedConsumerId)); 157 158 EXPECT_FALSE(base::PathExists(dump_file)); 159 160 base::DeleteFile(dump_file, false); 161 } 162 163 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY) 164 // Timing out on ARM linux bot: http://crbug.com/238490 165 #define MAYBE_TwoCallsWithAecDump DISABLED_TwoCallsWithAecDump 166 #elif defined(OS_ANDROID) && defined(ADDRESS_SANITIZER) 167 // Renderer crashes under Android ASAN: https://crbug.com/408496. 168 #define MAYBE_TwoCallsWithAecDump DISABLED_TwoCallsWithAecDump 169 #else 170 #define MAYBE_TwoCallsWithAecDump TwoCallsWithAecDump 171 #endif 172 173 IN_PROC_BROWSER_TEST_F(WebRtcAecDumpBrowserTest, MAYBE_TwoCallsWithAecDump) { 174 if (!media::AudioManager::Get()->HasAudioOutputDevices()) { 175 LOG(INFO) << "Missing output devices: skipping test..."; 176 return; 177 } 178 179 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 180 181 // We must navigate somewhere first so that the render process is created. 182 NavigateToURL(shell(), GURL("")); 183 184 // Create a second window. 185 Shell* shell2 = CreateBrowser(); 186 NavigateToURL(shell2, GURL("")); 187 188 base::FilePath dump_file; 189 ASSERT_TRUE(CreateTemporaryFile(&dump_file)); 190 base::DeleteFile(dump_file, false); 191 192 // This fakes the behavior of another open tab with webrtc-internals, and 193 // enabling AEC dump in that tab. 194 WebRTCInternals::GetInstance()->FileSelected(dump_file, -1, NULL); 195 196 GURL url(embedded_test_server()->GetURL("/media/peerconnection-call.html")); 197 198 NavigateToURL(shell(), url); 199 NavigateToURL(shell2, url); 200 ExecuteJavascriptAndWaitForOk("call({video: true, audio: true});"); 201 std::string result; 202 EXPECT_TRUE(ExecuteScriptAndExtractString( 203 shell2->web_contents(), 204 "call({video: true, audio: true});", 205 &result)); 206 ASSERT_STREQ("OK", result.c_str()); 207 208 EXPECT_FALSE(base::PathExists(dump_file)); 209 210 RenderProcessHost::iterator it = 211 content::RenderProcessHost::AllHostsIterator(); 212 for (; !it.IsAtEnd(); it.Advance()) { 213 base::ProcessId render_process_id = 214 base::GetProcId(it.GetCurrentValue()->GetHandle()); 215 EXPECT_NE(base::kNullProcessId, render_process_id); 216 217 // Add file extensions that we expect to be added. 218 base::FilePath unique_dump_file = 219 dump_file.AddExtension(IntToStringType(render_process_id)) 220 .AddExtension(IntToStringType(kExpectedConsumerId)); 221 222 EXPECT_TRUE(base::PathExists(unique_dump_file)); 223 int64 file_size = 0; 224 EXPECT_TRUE(base::GetFileSize(unique_dump_file, &file_size)); 225 EXPECT_GT(file_size, 0); 226 227 base::DeleteFile(unique_dump_file, false); 228 } 229 } 230 231 } // namespace content 232