1 // Copyright 2015 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.
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"
18 #define IntToStringType base::IntToString16
20 #define IntToStringType base::IntToString
25 const int kExpectedConsumerId
= 1;
26 const int kExpectedStreamId
= 1;
28 // Get the ID for the render process host when there should only be one.
29 bool GetRenderProcessHostId(base::ProcessId
* id
) {
30 content::RenderProcessHost::iterator
it(
31 content::RenderProcessHost::AllHostsIterator());
32 *id
= base::GetProcId(it
.GetCurrentValue()->GetHandle());
33 EXPECT_NE(base::kNullProcessId
, *id
);
34 if (*id
== base::kNullProcessId
)
37 EXPECT_TRUE(it
.IsAtEnd());
41 // Get the expected AEC dump file name. The name will be
42 // <temporary path>.<render process id>.aec_dump.<consumer id>, for example
43 // "/tmp/.com.google.Chrome.Z6UC3P.12345.aec_dump.1".
44 base::FilePath
GetExpectedAecDumpFileName(const base::FilePath
& base_file
,
45 int render_process_id
) {
46 return base_file
.AddExtension(IntToStringType(render_process_id
))
47 .AddExtension(FILE_PATH_LITERAL("aec_dump"))
48 .AddExtension(IntToStringType(kExpectedConsumerId
));
51 // Get the expected input audio file name. The name will be
52 // <temporary path>.<render process id>.source_input.<stream id>.pcm, for
53 // example "/tmp/.com.google.Chrome.Z6UC3P.12345.source_input.1.pcm".
54 base::FilePath
GetExpectedInputAudioFileName(const base::FilePath
& base_file
,
55 int render_process_id
) {
56 return base_file
.AddExtension(IntToStringType(render_process_id
))
57 .AddExtension(FILE_PATH_LITERAL("source_input"))
58 .AddExtension(IntToStringType(kExpectedStreamId
))
59 .AddExtension(FILE_PATH_LITERAL("pcm"));
66 class WebRtcAudioDebugRecordingsBrowserTest
: public WebRtcContentBrowserTest
{
68 WebRtcAudioDebugRecordingsBrowserTest() {}
69 ~WebRtcAudioDebugRecordingsBrowserTest() override
{}
72 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
73 // Timing out on ARM linux bot: http://crbug.com/238490
74 #define MAYBE_CallWithAudioDebugRecordings DISABLED_CallWithAudioDebugRecordings
75 #elif defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)
76 // Renderer crashes under Android ASAN: https://crbug.com/408496.
77 #define MAYBE_CallWithAudioDebugRecordings DISABLED_CallWithAudioDebugRecordings
79 #define MAYBE_CallWithAudioDebugRecordings CallWithAudioDebugRecordings
82 // This tests will make a complete PeerConnection-based call, verify that
83 // video is playing for the call, and verify that a non-empty AEC dump file
84 // exists. The AEC dump is enabled through webrtc-internals. The HTML and
85 // Javascript is bypassed since it would trigger a file picker dialog. Instead,
86 // the dialog callback FileSelected() is invoked directly. In fact, there's
87 // never a webrtc-internals page opened at all since that's not needed.
88 IN_PROC_BROWSER_TEST_F(WebRtcAudioDebugRecordingsBrowserTest
,
89 MAYBE_CallWithAudioDebugRecordings
) {
90 if (!media::AudioManager::Get()->HasAudioOutputDevices()) {
91 LOG(INFO
) << "Missing output devices: skipping test...";
95 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
97 // We must navigate somewhere first so that the render process is created.
98 NavigateToURL(shell(), GURL(""));
100 base::FilePath base_file
;
101 ASSERT_TRUE(CreateTemporaryFile(&base_file
));
102 base::DeleteFile(base_file
, false);
104 // This fakes the behavior of another open tab with webrtc-internals, and
105 // enabling AEC dump in that tab.
106 WebRTCInternals::GetInstance()->FileSelected(base_file
, -1, NULL
);
108 GURL
url(embedded_test_server()->GetURL("/media/peerconnection-call.html"));
109 NavigateToURL(shell(), url
);
110 ExecuteJavascriptAndWaitForOk("call({video: true, audio: true});");
112 EXPECT_FALSE(base::PathExists(base_file
));
114 // Verify that the expected AEC dump file exists and contains some data.
115 base::ProcessId render_process_id
= base::kNullProcessId
;
116 EXPECT_TRUE(GetRenderProcessHostId(&render_process_id
));
117 base::FilePath aec_dump_file
= GetExpectedAecDumpFileName(base_file
,
120 EXPECT_TRUE(base::PathExists(aec_dump_file
));
122 EXPECT_TRUE(base::GetFileSize(aec_dump_file
, &file_size
));
123 EXPECT_GT(file_size
, 0);
125 base::DeleteFile(aec_dump_file
, false);
127 // Verify that the expected input audio file exists and contains some data.
128 base::FilePath input_audio_file
=
129 GetExpectedInputAudioFileName(base_file
, render_process_id
);
131 EXPECT_TRUE(base::PathExists(input_audio_file
));
133 EXPECT_TRUE(base::GetFileSize(input_audio_file
, &file_size
));
134 EXPECT_GT(file_size
, 0);
136 base::DeleteFile(input_audio_file
, false);
139 // TODO(grunell): Add test for multiple dumps when re-use of
140 // MediaStreamAudioProcessor in AudioCapturer has been removed.
142 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
143 // Timing out on ARM linux bot: http://crbug.com/238490
144 #define MAYBE_CallWithAudioDebugRecordingsEnabledThenDisabled DISABLED_CallWithAudioDebugRecordingsEnabledThenDisabled
145 #elif defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)
146 // Renderer crashes under Android ASAN: https://crbug.com/408496.
147 #define MAYBE_CallWithAudioDebugRecordingsEnabledThenDisabled DISABLED_CallWithAudioDebugRecordingsEnabledThenDisabled
149 #define MAYBE_CallWithAudioDebugRecordingsEnabledThenDisabled CallWithAudioDebugRecordingsEnabledThenDisabled
152 // As above, but enable and disable dump before starting a call. The file should
153 // be created, but should be empty.
154 IN_PROC_BROWSER_TEST_F(WebRtcAudioDebugRecordingsBrowserTest
,
155 MAYBE_CallWithAudioDebugRecordingsEnabledThenDisabled
) {
156 if (!media::AudioManager::Get()->HasAudioOutputDevices()) {
157 LOG(INFO
) << "Missing output devices: skipping test...";
161 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
163 // We must navigate somewhere first so that the render process is created.
164 NavigateToURL(shell(), GURL(""));
166 base::FilePath base_file
;
167 ASSERT_TRUE(CreateTemporaryFile(&base_file
));
168 base::DeleteFile(base_file
, false);
170 // This fakes the behavior of another open tab with webrtc-internals, and
171 // enabling AEC dump in that tab, then disabling it.
172 WebRTCInternals::GetInstance()->FileSelected(base_file
, -1, NULL
);
173 WebRTCInternals::GetInstance()->DisableAudioDebugRecordings();
175 GURL
url(embedded_test_server()->GetURL("/media/peerconnection-call.html"));
176 NavigateToURL(shell(), url
);
177 ExecuteJavascriptAndWaitForOk("call({video: true, audio: true});");
179 // Verify that the expected AEC dump file doesn't exist.
180 base::ProcessId render_process_id
= base::kNullProcessId
;
181 EXPECT_TRUE(GetRenderProcessHostId(&render_process_id
));
182 base::FilePath aec_dump_file
= GetExpectedAecDumpFileName(base_file
,
184 EXPECT_FALSE(base::PathExists(aec_dump_file
));
185 base::DeleteFile(aec_dump_file
, false);
187 // Verify that the expected input audio file doesn't exist.
188 base::FilePath input_audio_file
=
189 GetExpectedInputAudioFileName(base_file
, render_process_id
);
190 EXPECT_FALSE(base::PathExists(input_audio_file
));
191 base::DeleteFile(input_audio_file
, false);
194 // Timing out on ARM linux bot: http://crbug.com/238490
195 // Renderer crashes under Android ASAN: https://crbug.com/408496.
196 // Flaky on XP and Mac: http://crbug.com/425034.
197 IN_PROC_BROWSER_TEST_F(WebRtcAudioDebugRecordingsBrowserTest
,
198 DISABLED_TwoCallsWithAudioDebugRecordings
) {
200 LOG(INFO
) << "Disabled on Win XP: skipping test...";
203 if (!media::AudioManager::Get()->HasAudioOutputDevices()) {
204 LOG(INFO
) << "Missing output devices: skipping test...";
208 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
210 // We must navigate somewhere first so that the render process is created.
211 NavigateToURL(shell(), GURL(""));
213 // Create a second window.
214 Shell
* shell2
= CreateBrowser();
215 NavigateToURL(shell2
, GURL(""));
217 base::FilePath base_file
;
218 ASSERT_TRUE(CreateTemporaryFile(&base_file
));
219 base::DeleteFile(base_file
, false);
221 // This fakes the behavior of another open tab with webrtc-internals, and
222 // enabling AEC dump in that tab.
223 WebRTCInternals::GetInstance()->FileSelected(base_file
, -1, NULL
);
225 GURL
url(embedded_test_server()->GetURL("/media/peerconnection-call.html"));
227 NavigateToURL(shell(), url
);
228 NavigateToURL(shell2
, url
);
229 ExecuteJavascriptAndWaitForOk("call({video: true, audio: true});");
231 EXPECT_TRUE(ExecuteScriptAndExtractString(
232 shell2
->web_contents(),
233 "call({video: true, audio: true});",
235 ASSERT_STREQ("OK", result
.c_str());
237 EXPECT_FALSE(base::PathExists(base_file
));
239 RenderProcessHost::iterator it
=
240 content::RenderProcessHost::AllHostsIterator();
242 for (; !it
.IsAtEnd(); it
.Advance()) {
243 base::ProcessId render_process_id
=
244 base::GetProcId(it
.GetCurrentValue()->GetHandle());
245 EXPECT_NE(base::kNullProcessId
, render_process_id
);
247 // Verify that the expected AEC dump file exists and contains some data.
248 base::FilePath aec_dump_file
=
249 GetExpectedAecDumpFileName(base_file
, render_process_id
);
251 EXPECT_TRUE(base::PathExists(aec_dump_file
));
253 EXPECT_TRUE(base::GetFileSize(aec_dump_file
, &file_size
));
254 EXPECT_GT(file_size
, 0);
256 base::DeleteFile(aec_dump_file
, false);
258 // Verify that the expected input audio file exists and contains some data.
259 base::FilePath input_audio_file
=
260 GetExpectedInputAudioFileName(base_file
, render_process_id
);
262 EXPECT_TRUE(base::PathExists(input_audio_file
));
264 EXPECT_TRUE(base::GetFileSize(input_audio_file
, &file_size
));
265 EXPECT_GT(file_size
, 0);
267 base::DeleteFile(input_audio_file
, false);
271 } // namespace content