Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(90)

Side by Side Diff: chrome/browser/media/chrome_webrtc_audio_quality_browsertest.cc

Issue 799983002: Adding WebRTC Auto Gain Control Test (linux) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Now computing a whole segment at a time, simplified code. Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | chrome/browser/media/webrtc_browsertest_audio.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <ctime> 5 #include <ctime>
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/files/file_enumerator.h"
8 #include "base/files/file_util.h" 9 #include "base/files/file_util.h"
10 #include "base/files/scoped_temp_dir.h"
9 #include "base/process/launch.h" 11 #include "base/process/launch.h"
10 #include "base/process/process.h" 12 #include "base/process/process.h"
11 #include "base/scoped_native_library.h" 13 #include "base/scoped_native_library.h"
14 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h" 15 #include "base/strings/stringprintf.h"
16 #include "chrome/browser/media/webrtc_browsertest_audio.h"
13 #include "chrome/browser/media/webrtc_browsertest_base.h" 17 #include "chrome/browser/media/webrtc_browsertest_base.h"
14 #include "chrome/browser/media/webrtc_browsertest_common.h" 18 #include "chrome/browser/media/webrtc_browsertest_common.h"
15 #include "chrome/browser/profiles/profile.h" 19 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/ui/browser.h" 20 #include "chrome/browser/ui/browser.h"
17 #include "chrome/browser/ui/browser_tabstrip.h" 21 #include "chrome/browser/ui/browser_tabstrip.h"
18 #include "chrome/browser/ui/tabs/tab_strip_model.h" 22 #include "chrome/browser/ui/tabs/tab_strip_model.h"
19 #include "chrome/common/chrome_paths.h" 23 #include "chrome/common/chrome_paths.h"
20 #include "chrome/common/chrome_switches.h" 24 #include "chrome/common/chrome_switches.h"
21 #include "chrome/test/base/ui_test_utils.h" 25 #include "chrome/test/base/ui_test_utils.h"
22 #include "content/public/test/browser_test_utils.h" 26 #include "content/public/test/browser_test_utils.h"
27 #include "media/audio/audio_parameters.h"
23 #include "media/base/media_switches.h" 28 #include "media/base/media_switches.h"
24 #include "net/test/embedded_test_server/embedded_test_server.h" 29 #include "net/test/embedded_test_server/embedded_test_server.h"
25 #include "testing/perf/perf_test.h" 30 #include "testing/perf/perf_test.h"
26 31
27 // These are relative to the reference file dir defined by 32 // These are relative to the reference file dir defined by
28 // webrtc_browsertest_common.h (i.e. chrome/test/data/webrtc/resources). 33 // webrtc_browsertest_common.h (i.e. chrome/test/data/webrtc/resources).
29 static const base::FilePath::CharType kReferenceFile[] = 34 static const base::FilePath::CharType kReferenceFile[] =
30 #if defined (OS_WIN) 35 #if defined (OS_WIN)
31 FILE_PATH_LITERAL("human-voice-win.wav"); 36 FILE_PATH_LITERAL("human-voice-win.wav");
32 #elif defined (OS_MACOSX) 37 #elif defined (OS_MACOSX)
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
142 content::WebContents* tab_contents) { 147 content::WebContents* tab_contents) {
143 // This calls into webaudio.js. 148 // This calls into webaudio.js.
144 EXPECT_EQ("ok-added", ExecuteJavascript( 149 EXPECT_EQ("ok-added", ExecuteJavascript(
145 "addAudioFile('" + input_file_relative_url + "')", tab_contents)); 150 "addAudioFile('" + input_file_relative_url + "')", tab_contents));
146 } 151 }
147 152
148 void PlayAudioFileThroughWebAudio(content::WebContents* tab_contents) { 153 void PlayAudioFileThroughWebAudio(content::WebContents* tab_contents) {
149 EXPECT_EQ("ok-playing", ExecuteJavascript("playAudioFile()", tab_contents)); 154 EXPECT_EQ("ok-playing", ExecuteJavascript("playAudioFile()", tab_contents));
150 } 155 }
151 156
152 base::FilePath CreateTemporaryWaveFile() {
153 base::FilePath filename;
154 EXPECT_TRUE(base::CreateTemporaryFile(&filename));
155 base::FilePath wav_filename =
156 filename.AddExtension(FILE_PATH_LITERAL(".wav"));
157 EXPECT_TRUE(base::Move(filename, wav_filename));
158 return wav_filename;
159 }
160
161 content::WebContents* OpenPageWithoutGetUserMedia(const char* url) { 157 content::WebContents* OpenPageWithoutGetUserMedia(const char* url) {
162 chrome::AddTabAt(browser(), GURL(), -1, true); 158 chrome::AddTabAt(browser(), GURL(), -1, true);
163 ui_test_utils::NavigateToURL( 159 ui_test_utils::NavigateToURL(
164 browser(), embedded_test_server()->GetURL(url)); 160 browser(), embedded_test_server()->GetURL(url));
165 content::WebContents* tab = 161 content::WebContents* tab =
166 browser()->tab_strip_model()->GetActiveWebContents(); 162 browser()->tab_strip_model()->GetActiveWebContents();
167 163
168 // Prepare the peer connections manually in this test since we don't add 164 // Prepare the peer connections manually in this test since we don't add
169 // getUserMedia-derived media streams in this test like the other tests. 165 // getUserMedia-derived media streams in this test like the other tests.
170 EXPECT_EQ("ok-peerconnection-created", 166 EXPECT_EQ("ok-peerconnection-created",
171 ExecuteJavascript("preparePeerConnection()", tab)); 167 ExecuteJavascript("preparePeerConnection()", tab));
172 return tab; 168 return tab;
173 } 169 }
170
171 protected:
172 void TestAutoGainControl(const base::FilePath::StringType& reference_filename,
173 const std::string& constraints,
174 const std::string& perf_modifier);
174 }; 175 };
175 176
177 namespace {
178
176 class AudioRecorder { 179 class AudioRecorder {
177 public: 180 public:
178 AudioRecorder() {} 181 AudioRecorder() {}
179 ~AudioRecorder() {} 182 ~AudioRecorder() {}
180 183
181 // Starts the recording program for the specified duration. Returns true 184 // Starts the recording program for the specified duration. Returns true
182 // on success. 185 // on success. We record in CD format unless record_cd is false, in which case
henrika (OOO until Aug 14) 2014/12/19 10:00:14 |record_cd| and please don't use CD/DAT format. Be
phoglund_chromium 2014/12/19 10:34:20 Done.
186 // we record in DAT format.
187 // TODO(phoglund): make win and mac also support the record_cd parameter. Or,
188 // even better, make everybody use the CD format rather than DAT.
183 bool StartRecording(int duration_sec, const base::FilePath& output_file, 189 bool StartRecording(int duration_sec, const base::FilePath& output_file,
184 bool mono) { 190 bool mono, bool record_cd) {
185 EXPECT_FALSE(recording_application_.IsValid()) 191 EXPECT_FALSE(recording_application_.IsValid())
186 << "Tried to record, but is already recording."; 192 << "Tried to record, but is already recording.";
187 193
188 CommandLine command_line(CommandLine::NO_PROGRAM); 194 CommandLine command_line(CommandLine::NO_PROGRAM);
189 #if defined(OS_WIN) 195 #if defined(OS_WIN)
190 // This disable is required to run SoundRecorder.exe on 64-bit Windows 196 // This disable is required to run SoundRecorder.exe on 64-bit Windows
191 // from a 32-bit binary. We need to load the wow64 disable function from 197 // from a 32-bit binary. We need to load the wow64 disable function from
192 // the DLL since it doesn't exist on Windows XP. 198 // the DLL since it doesn't exist on Windows XP.
193 // TODO(phoglund): find some cleaner solution than using SoundRecorder.exe. 199 // TODO(phoglund): find some cleaner solution than using SoundRecorder.exe.
194 base::ScopedNativeLibrary kernel32_lib(base::FilePath(L"kernel32")); 200 base::ScopedNativeLibrary kernel32_lib(base::FilePath(L"kernel32"));
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 if (mono) { 237 if (mono) {
232 command_line.AppendArg("remix"); 238 command_line.AppendArg("remix");
233 command_line.AppendArg("-"); 239 command_line.AppendArg("-");
234 } 240 }
235 #else 241 #else
236 int num_channels = mono ? 1 : 2; 242 int num_channels = mono ? 1 : 2;
237 command_line.SetProgram(base::FilePath("arecord")); 243 command_line.SetProgram(base::FilePath("arecord"));
238 command_line.AppendArg("-d"); 244 command_line.AppendArg("-d");
239 command_line.AppendArg(base::StringPrintf("%d", duration_sec)); 245 command_line.AppendArg(base::StringPrintf("%d", duration_sec));
240 command_line.AppendArg("-f"); 246 command_line.AppendArg("-f");
241 command_line.AppendArg("dat"); 247 if (record_cd)
248 command_line.AppendArg("cd");
249 else
250 command_line.AppendArg("dat");
242 command_line.AppendArg("-c"); 251 command_line.AppendArg("-c");
243 command_line.AppendArg(base::StringPrintf("%d", num_channels)); 252 command_line.AppendArg(base::StringPrintf("%d", num_channels));
244 command_line.AppendArgPath(output_file); 253 command_line.AppendArgPath(output_file);
245 #endif 254 #endif
246 255
247 DVLOG(0) << "Running " << command_line.GetCommandLineString(); 256 DVLOG(0) << "Running " << command_line.GetCommandLineString();
248 recording_application_ = 257 recording_application_ =
249 base::LaunchProcess(command_line, base::LaunchOptions()); 258 base::LaunchProcess(command_line, base::LaunchOptions());
250 return recording_application_.IsValid(); 259 return recording_application_.IsValid();
251 } 260 }
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 DVLOG(0) << "Running " << command_line.GetCommandLineString(); 306 DVLOG(0) << "Running " << command_line.GetCommandLineString();
298 if (!base::GetAppOutput(command_line, &result)) { 307 if (!base::GetAppOutput(command_line, &result)) {
299 LOG(ERROR) << "Failed to set source volume: output was " << result; 308 LOG(ERROR) << "Failed to set source volume: output was " << result;
300 return false; 309 return false;
301 } 310 }
302 } 311 }
303 #endif 312 #endif
304 return true; 313 return true;
305 } 314 }
306 315
316 CommandLine MakeSoxCommandLine() {
henrika (OOO until Aug 14) 2014/12/19 10:00:14 Could you add some comments and reference to SoX?
phoglund_chromium 2014/12/19 10:34:20 Done.
317 #if defined(OS_WIN)
318 base::FilePath sox_path = test::GetReferenceFilesDir().Append(
319 FILE_PATH_LITERAL("tools/sox.exe"));
320 if (!base::PathExists(sox_path)) {
321 LOG(ERROR) << "Missing sox.exe binary in " << sox_path.value()
322 << "; you may have to provide this binary yourself.";
323 return false;
324 }
325 CommandLine command_line(sox_path);
326 #else
327 CommandLine command_line(base::FilePath(FILE_PATH_LITERAL("sox")));
328 #endif
329 return command_line;
330 }
331
307 // Removes silence from beginning and end of the |input_audio_file| and writes 332 // Removes silence from beginning and end of the |input_audio_file| and writes
308 // the result to the |output_audio_file|. Returns true on success. 333 // the result to the |output_audio_file|. Returns true on success.
309 bool RemoveSilence(const base::FilePath& input_file, 334 bool RemoveSilence(const base::FilePath& input_file,
310 const base::FilePath& output_file) { 335 const base::FilePath& output_file) {
311 // SOX documentation for silence command: http://sox.sourceforge.net/sox.html 336 // SOX documentation for silence command: http://sox.sourceforge.net/sox.html
312 // To remove the silence from both beginning and end of the audio file, we 337 // To remove the silence from both beginning and end of the audio file, we
313 // call sox silence command twice: once on normal file and again on its 338 // call sox silence command twice: once on normal file and again on its
314 // reverse, then we reverse the final output. 339 // reverse, then we reverse the final output.
315 // Silence parameters are (in sequence): 340 // Silence parameters are (in sequence):
316 // ABOVE_PERIODS: The period for which silence occurs. Value 1 is used for 341 // ABOVE_PERIODS: The period for which silence occurs. Value 1 is used for
317 // silence at beginning of audio. 342 // silence at beginning of audio.
318 // DURATION: the amount of time in seconds that non-silence must be detected 343 // DURATION: the amount of time in seconds that non-silence must be detected
319 // before sox stops trimming audio. 344 // before sox stops trimming audio.
320 // THRESHOLD: value used to indicate what sample value is treates as silence. 345 // THRESHOLD: value used to indicate what sample value is treats as silence.
321 const char* kAbovePeriods = "1"; 346 const char* kAbovePeriods = "1";
henrika (OOO until Aug 14) 2014/12/19 10:00:14 How essential are these exact parameter values for
phoglund_chromium 2014/12/19 10:34:20 It depends a lot on the files we feed in. With the
322 const char* kDuration = "2"; 347 const char* kDuration = "2";
323 const char* kTreshold = "5%"; 348 const char* kTreshold = "3%";
324 349
325 #if defined(OS_WIN) 350 CommandLine command_line = MakeSoxCommandLine();
326 base::FilePath sox_path = test::GetReferenceFilesDir().Append(
327 FILE_PATH_LITERAL("tools/sox.exe"));
328 if (!base::PathExists(sox_path)) {
329 LOG(ERROR) << "Missing sox.exe binary in " << sox_path.value()
330 << "; you may have to provide this binary yourself.";
331 return false;
332 }
333 CommandLine command_line(sox_path);
334 #else
335 CommandLine command_line(base::FilePath(FILE_PATH_LITERAL("sox")));
336 #endif
337 command_line.AppendArgPath(input_file); 351 command_line.AppendArgPath(input_file);
338 command_line.AppendArgPath(output_file); 352 command_line.AppendArgPath(output_file);
339 command_line.AppendArg("silence"); 353 command_line.AppendArg("silence");
340 command_line.AppendArg(kAbovePeriods); 354 command_line.AppendArg(kAbovePeriods);
341 command_line.AppendArg(kDuration); 355 command_line.AppendArg(kDuration);
342 command_line.AppendArg(kTreshold); 356 command_line.AppendArg(kTreshold);
343 command_line.AppendArg("reverse"); 357 command_line.AppendArg("reverse");
344 command_line.AppendArg("silence"); 358 command_line.AppendArg("silence");
345 command_line.AppendArg(kAbovePeriods); 359 command_line.AppendArg(kAbovePeriods);
346 command_line.AppendArg(kDuration); 360 command_line.AppendArg(kDuration);
347 command_line.AppendArg(kTreshold); 361 command_line.AppendArg(kTreshold);
348 command_line.AppendArg("reverse"); 362 command_line.AppendArg("reverse");
349 363
350 DVLOG(0) << "Running " << command_line.GetCommandLineString(); 364 DVLOG(0) << "Running " << command_line.GetCommandLineString();
351 std::string result; 365 std::string result;
352 bool ok = base::GetAppOutput(command_line, &result); 366 bool ok = base::GetAppOutput(command_line, &result);
353 DVLOG(0) << "Output was:\n\n" << result; 367 DVLOG(0) << "Output was:\n\n" << result;
354 return ok; 368 return ok;
355 } 369 }
356 370
371 // Looks for 0.3-second silences (under 1% audio power) and splits the input
372 // file on those silences. Output files are written according to the output file
373 // template (e.g. /tmp/out.wav writes /tmp/out001.wav, /tmp/out002.wav, etc if
374 // there are two silence-padded regions in the file). The silences between
375 // speech segments must be at least 500 ms for this to be reliable.
376 bool SplitFileOnSilence(const base::FilePath& input_file,
377 const base::FilePath& output_file_template) {
378 CommandLine command_line = MakeSoxCommandLine();
379
380 // These are experimentally determined and work on the files we use.
381 const char* kAbovePeriods = "1";
382 const char* kUnderPeriods = "1";
383 const char* kDuration = "0.3";
384 const char* kTreshold = "1%";
385 command_line.AppendArgPath(input_file);
386 command_line.AppendArgPath(output_file_template);
387 command_line.AppendArg("silence");
388 command_line.AppendArg(kAbovePeriods);
389 command_line.AppendArg(kDuration);
390 command_line.AppendArg(kTreshold);
391 command_line.AppendArg(kUnderPeriods);
392 command_line.AppendArg(kDuration);
393 command_line.AppendArg(kTreshold);
394 command_line.AppendArg(":");
395 command_line.AppendArg("newfile");
396 command_line.AppendArg(":");
397 command_line.AppendArg("restart");
398
399 DVLOG(0) << "Running " << command_line.GetCommandLineString();
400 std::string result;
401 bool ok = base::GetAppOutput(command_line, &result);
402 DVLOG(0) << "Output was:\n\n" << result;
403 return ok;
404 }
405
357 bool CanParseAsFloat(const std::string& value) { 406 bool CanParseAsFloat(const std::string& value) {
358 return atof(value.c_str()) != 0 || value == "0"; 407 return atof(value.c_str()) != 0 || value == "0";
359 } 408 }
360 409
361 // Runs PESQ to compare |reference_file| to a |actual_file|. The |sample_rate| 410 // Runs PESQ to compare |reference_file| to a |actual_file|. The |sample_rate|
362 // can be either 16000 or 8000. 411 // can be either 16000 or 8000.
363 // 412 //
364 // PESQ is only mono-aware, so the files should preferably be recorded in mono. 413 // PESQ is only mono-aware, so the files should preferably be recorded in mono.
365 // Furthermore it expects the file to be 16 rather than 32 bits, even though 414 // Furthermore it expects the file to be 16 rather than 32 bits, even though
366 // 32 bits might work. The audio bandwidth of the two files should be the same 415 // 32 bits might work. The audio bandwidth of the two files should be the same
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
417 // There are two tab-separated numbers on the format x.xxx, e.g. 5 chars each. 466 // There are two tab-separated numbers on the format x.xxx, e.g. 5 chars each.
418 std::size_t first_number_pos = anchor_pos + result_anchor.length(); 467 std::size_t first_number_pos = anchor_pos + result_anchor.length();
419 *raw_mos = result.substr(first_number_pos, 5); 468 *raw_mos = result.substr(first_number_pos, 5);
420 EXPECT_TRUE(CanParseAsFloat(*raw_mos)) << "Failed to parse raw MOS number."; 469 EXPECT_TRUE(CanParseAsFloat(*raw_mos)) << "Failed to parse raw MOS number.";
421 *mos_lqo = result.substr(first_number_pos + 5 + 1, 5); 470 *mos_lqo = result.substr(first_number_pos + 5 + 1, 5);
422 EXPECT_TRUE(CanParseAsFloat(*mos_lqo)) << "Failed to parse MOS LQO number."; 471 EXPECT_TRUE(CanParseAsFloat(*mos_lqo)) << "Failed to parse MOS LQO number.";
423 472
424 return true; 473 return true;
425 } 474 }
426 475
476 base::FilePath CreateTemporaryWaveFile() {
477 base::FilePath filename;
478 EXPECT_TRUE(base::CreateTemporaryFile(&filename));
479 base::FilePath wav_filename =
480 filename.AddExtension(FILE_PATH_LITERAL(".wav"));
481 EXPECT_TRUE(base::Move(filename, wav_filename));
482 return wav_filename;
483 }
484
485 std::vector<base::FilePath> ListWavFilesInDir(const base::FilePath& dir) {
486 base::FileEnumerator files(dir, false, base::FileEnumerator::FILES,
487 FILE_PATH_LITERAL("*.wav"));
488
489 std::vector<base::FilePath> result;
490 for (base::FilePath name = files.Next(); !name.empty(); name = files.Next())
491 result.push_back(name);
492 return result;
493 }
494
495 // Splits |to_split| into sub-files base on silence. The file you use must have
henrika (OOO until Aug 14) 2014/12/19 10:00:14 nit, 'based on'
phoglund_chromium 2014/12/19 10:34:20 Done.
496 // at least 500 ms periods of silence between speech segments for this to be
497 // reliable.
498 void SplitFileOnSilenceIntoDir(const base::FilePath& to_split,
499 const base::FilePath& workdir) {
500 // First trim beginning and end since they are tricky for the splitter.
501 base::FilePath trimmed_audio = CreateTemporaryWaveFile();
502
503 ASSERT_TRUE(RemoveSilence(to_split, trimmed_audio));
504 DVLOG(0) << "Trimmed silence: " << trimmed_audio.value() << std::endl;
505
506 ASSERT_TRUE(SplitFileOnSilence(trimmed_audio, workdir.Append("output.wav")));
507 ASSERT_TRUE(base::DeleteFile(trimmed_audio, false));
508 }
509
510 // Computes the difference between the actual and reference segment. A positive
511 // number x means the actual file is x dB stronger than the reference.
512 float AnalyzeOneSegment(const base::FilePath& ref_segment,
513 const base::FilePath& actual_segment,
514 int segment_number) {
515 media::AudioParameters ref_parameters;
516 media::AudioParameters actual_parameters;
517 float ref_energy =
518 test::ComputeAudioEnergyForWavFile(ref_segment, &ref_parameters);
519 float actual_energy =
520 test::ComputeAudioEnergyForWavFile(actual_segment, &actual_parameters);
521
522 base::TimeDelta difference_in_length = ref_parameters.GetBufferDuration() -
523 actual_parameters.GetBufferDuration();
524 EXPECT_LE(difference_in_length, base::TimeDelta::FromMilliseconds(200))
525 << "Segments differ " << difference_in_length.InMilliseconds() << " ms "
526 << "in length for segment " << segment_number << "; we're likely "
527 << "comparing unrelated segments or silence splitting is busted.";
528
529 return actual_energy - ref_energy;
530 }
531
532 void AnalyzeSegmentsAndPrintResult(
533 const std::vector<base::FilePath>& ref_segments,
534 const std::vector<base::FilePath>& actual_segments,
535 const base::FilePath& reference_file,
536 const std::string& perf_modifier) {
537 ASSERT_GT(ref_segments.size(), 0u)
538 << "Failed to split reference file on silence; sox is likely broken.";
539 ASSERT_EQ(ref_segments.size(), actual_segments.size())
540 << "The recording did not result in the same number of audio segments "
541 << "after on splitting on silence; WebRTC must have deformed the audio "
542 << "too much.";
543
544 for (size_t i = 0; i < ref_segments.size(); i++) {
545 float difference_in_decibel = AnalyzeOneSegment(ref_segments[i],
546 actual_segments[i],
547 i);
548 std::string trace_name = base::StringPrintf(
549 "%s_segment_%zu", reference_file.BaseName().value().c_str(), i);
550 perf_test::PrintResult("agc_energy_diff", perf_modifier, trace_name,
551 difference_in_decibel, "dB", false);
552 }
553 }
554
555 } // namespace
556
427 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioQualityBrowserTest, 557 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioQualityBrowserTest,
428 MANUAL_TestAudioQuality) { 558 MANUAL_TestAudioQuality) {
429 if (OnWinXp()) { 559 if (OnWinXp()) {
430 LOG(ERROR) << "This test is not implemented for Windows XP."; 560 LOG(ERROR) << "This test is not implemented for Windows XP.";
431 return; 561 return;
432 } 562 }
433 if (OnWin8()) { 563 if (OnWin8()) {
434 // http://crbug.com/379798. 564 // http://crbug.com/379798.
435 LOG(ERROR) << "Temporarily disabled for Win 8."; 565 LOG(ERROR) << "Temporarily disabled for Win 8.";
436 return; 566 return;
(...skipping 16 matching lines...) Expand all
453 // because the ready state is ok on both sides. We sleep a bit between call 583 // because the ready state is ok on both sides. We sleep a bit between call
454 // establishment and playing to avoid cutting off the beginning of the stream. 584 // establishment and playing to avoid cutting off the beginning of the stream.
455 test::SleepInJavascript(left_tab, 2000); 585 test::SleepInJavascript(left_tab, 2000);
456 586
457 base::FilePath recording = CreateTemporaryWaveFile(); 587 base::FilePath recording = CreateTemporaryWaveFile();
458 588
459 // Note: the sound clip is about 10 seconds: record for 15 seconds to get some 589 // Note: the sound clip is about 10 seconds: record for 15 seconds to get some
460 // safety margins on each side. 590 // safety margins on each side.
461 AudioRecorder recorder; 591 AudioRecorder recorder;
462 static int kRecordingTimeSeconds = 15; 592 static int kRecordingTimeSeconds = 15;
463 ASSERT_TRUE(recorder.StartRecording(kRecordingTimeSeconds, recording, true)); 593 ASSERT_TRUE(recorder.StartRecording(kRecordingTimeSeconds, recording,
594 true, false));
464 595
465 PlayAudioFileThroughWebAudio(left_tab); 596 PlayAudioFileThroughWebAudio(left_tab);
466 597
467 ASSERT_TRUE(recorder.WaitForRecordingToEnd()); 598 ASSERT_TRUE(recorder.WaitForRecordingToEnd());
468 DVLOG(0) << "Done recording to " << recording.value() << std::endl; 599 DVLOG(0) << "Done recording to " << recording.value() << std::endl;
469 600
470 HangUp(left_tab); 601 HangUp(left_tab);
471 602
472 base::FilePath trimmed_recording = CreateTemporaryWaveFile(); 603 base::FilePath trimmed_recording = CreateTemporaryWaveFile();
473 604
474 ASSERT_TRUE(RemoveSilence(recording, trimmed_recording)); 605 ASSERT_TRUE(RemoveSilence(recording, trimmed_recording));
475 DVLOG(0) << "Trimmed silence: " << trimmed_recording.value() << std::endl; 606 DVLOG(0) << "Trimmed silence: " << trimmed_recording.value() << std::endl;
476 607
477 std::string raw_mos; 608 std::string raw_mos;
478 std::string mos_lqo; 609 std::string mos_lqo;
479 base::FilePath reference_file_in_test_dir = 610 base::FilePath reference_file_in_test_dir =
480 test::GetReferenceFilesDir().Append(kReferenceFile); 611 test::GetReferenceFilesDir().Append(kReferenceFile);
481 ASSERT_TRUE(RunPesq(reference_file_in_test_dir, trimmed_recording, 16000, 612 ASSERT_TRUE(RunPesq(reference_file_in_test_dir, trimmed_recording, 16000,
482 &raw_mos, &mos_lqo)); 613 &raw_mos, &mos_lqo));
483 614
484 perf_test::PrintResult("audio_pesq", "", "raw_mos", raw_mos, "score", true); 615 perf_test::PrintResult("audio_pesq", "", "raw_mos", raw_mos, "score", true);
485 perf_test::PrintResult("audio_pesq", "", "mos_lqo", mos_lqo, "score", true); 616 perf_test::PrintResult("audio_pesq", "", "mos_lqo", mos_lqo, "score", true);
486 617
487 EXPECT_TRUE(base::DeleteFile(recording, false)); 618 EXPECT_TRUE(base::DeleteFile(recording, false));
488 EXPECT_TRUE(base::DeleteFile(trimmed_recording, false)); 619 EXPECT_TRUE(base::DeleteFile(trimmed_recording, false));
489 } 620 }
490 621
491 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioQualityBrowserTest, 622 /**
492 MANUAL_TestAutoGainControlIncreasesEnergyForLowAudio) { 623 * The auto gain control test plays a file into the fake microphone. Then it
624 * sets up a one-way WebRTC call with audio only and records Chrome's output on
625 * the receiving side using the audio loopback provided by the quality test
626 * (see the class comments for more details).
627 *
628 * Then both the recording and reference file are split on silence. This creates
629 * a number of segments with speech in them. The reason for this is to provide
630 * a kind of synchronization mechanism so the start of each speech segment is
631 * compared to the start of the corresponding speech segment. This is because we
632 * will experience inevitable clock drift between the system clock (which runs
633 * the fake microphone) and the sound card (which runs play-out). Effectively
634 * re-synchronizing on each segment mitigates this.
635 *
636 * The silence splitting is inherently sensitive to the sound file we run on.
637 * Therefore the reference file must have at least 500 ms of pure silence
638 * between speech segments; the test will fail if the output produces more
639 * segments than the reference.
640 *
641 * The test reports the difference in decibel between the reference and output
642 * file per 10 ms interval in each speech segment. A value of 6 means the
643 * output was 6 dB louder than the reference, presumably because the AGC applied
644 * gain to the signal.
645 *
646 * The test only exercises digital AGC for now.
647 *
648 * We record in CD format here (44.1 kHz) because that's what the fake input
649 * device currently supports, and we want to be able to compare directly.
henrika (OOO until Aug 14) 2014/12/19 10:00:14 Any link to a crbug here?
phoglund_chromium 2014/12/19 10:34:20 Sure, I can link to the fake device bug where the
650 */
651 void MAYBE_WebRtcAudioQualityBrowserTest::TestAutoGainControl(
652 const base::FilePath::StringType& reference_filename,
653 const std::string& constraints,
654 const std::string& perf_modifier) {
493 if (OnWinXp()) { 655 if (OnWinXp()) {
494 LOG(ERROR) << "This test is not implemented for Windows XP."; 656 LOG(ERROR) << "This test is not implemented for Windows XP.";
495 return; 657 return;
496 } 658 }
497 if (OnWin8()) { 659 if (OnWin8()) {
498 // http://crbug.com/379798. 660 // http://crbug.com/379798.
499 LOG(ERROR) << "Temporarily disabled for Win 8."; 661 LOG(ERROR) << "Temporarily disabled for Win 8.";
500 return; 662 return;
501 } 663 }
502 ASSERT_TRUE(test::HasReferenceFilesInCheckout()); 664 ASSERT_TRUE(test::HasReferenceFilesInCheckout());
503 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 665 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
504 666
505 ASSERT_TRUE(ForceMicrophoneVolumeTo100Percent()); 667 ASSERT_TRUE(ForceMicrophoneVolumeTo100Percent());
506 668
507 ConfigureFakeDeviceToPlayFile( 669 base::FilePath reference_file =
508 test::GetReferenceFilesDir().Append(kAgcTestReferenceFile)); 670 test::GetReferenceFilesDir().Append(reference_filename);
671 ConfigureFakeDeviceToPlayFile(reference_file);
509 672
510 // Create a one-way call. 673 // Create a one-way call.
511 GURL test_page = embedded_test_server()->GetURL(kWebRtcAudioTestHtmlPage); 674 GURL test_page = embedded_test_server()->GetURL(kWebRtcAudioTestHtmlPage);
512 content::WebContents* left_tab = 675 content::WebContents* left_tab =
513 OpenPageAndGetUserMediaInNewTabWithConstraints(test_page, 676 OpenPageAndGetUserMediaInNewTabWithConstraints(test_page, constraints);
514 kAudioOnlyCallConstraints);
515 SetupPeerconnectionWithLocalStream(left_tab); 677 SetupPeerconnectionWithLocalStream(left_tab);
516 678
517 content::WebContents* right_tab = 679 content::WebContents* right_tab =
518 OpenPageWithoutGetUserMedia(kWebRtcAudioTestHtmlPage); 680 OpenPageWithoutGetUserMedia(kWebRtcAudioTestHtmlPage);
519 681
520 NegotiateCall(left_tab, right_tab);
521
522 base::FilePath recording = CreateTemporaryWaveFile(); 682 base::FilePath recording = CreateTemporaryWaveFile();
523 683
524 AudioRecorder recorder; 684 AudioRecorder recorder;
525 static int kRecordingTimeSeconds = 10; 685 static int kRecordingTimeSeconds = 25;
526 ASSERT_TRUE(recorder.StartRecording(kRecordingTimeSeconds, recording, true)); 686 ASSERT_TRUE(recorder.StartRecording(kRecordingTimeSeconds, recording, false,
687 true));
688
689 NegotiateCall(left_tab, right_tab);
527 690
528 ASSERT_TRUE(recorder.WaitForRecordingToEnd()); 691 ASSERT_TRUE(recorder.WaitForRecordingToEnd());
529 DVLOG(0) << "Done recording to " << recording.value() << std::endl; 692 DVLOG(0) << "Done recording to " << recording.value() << std::endl;
530 693
531 HangUp(left_tab); 694 HangUp(left_tab);
532 695
533 base::FilePath trimmed_recording = CreateTemporaryWaveFile(); 696 // Call Take() on the scoped temp dirs if you want to look at the files after
697 // the test exits (the default is to delete the files).
698 base::ScopedTempDir split_ref_files;
699 ASSERT_TRUE(split_ref_files.CreateUniqueTempDir());
700 ASSERT_NO_FATAL_FAILURE(
701 SplitFileOnSilenceIntoDir(reference_file, split_ref_files.path()));
702 std::vector<base::FilePath> ref_segments =
703 ListWavFilesInDir(split_ref_files.path());
534 704
535 ASSERT_TRUE(RemoveSilence(recording, trimmed_recording)); 705 base::ScopedTempDir split_actual_files;
536 DVLOG(0) << "Trimmed silence: " << trimmed_recording.value() << std::endl; 706 ASSERT_TRUE(split_actual_files.CreateUniqueTempDir());
707 ASSERT_NO_FATAL_FAILURE(
708 SplitFileOnSilenceIntoDir(recording, split_actual_files.path()));
709 std::vector<base::FilePath> actual_segments =
710 ListWavFilesInDir(split_actual_files.path());
537 711
538 // TODO(phoglund): invoke bjornv's audio energy analysis tool on the trimmed 712 AnalyzeSegmentsAndPrintResult(ref_segments, actual_segments, reference_file,
539 // recording and log the result. 713 perf_modifier);
540 714
541 EXPECT_TRUE(base::DeleteFile(recording, false)); 715 EXPECT_TRUE(base::DeleteFile(recording, false));
542 EXPECT_TRUE(base::DeleteFile(trimmed_recording, false));
543 } 716 }
717
718 // Only implemented for Linux for now.
719 #if defined(OS_LINUX)
720 #define MAYBE_MANUAL_TestAutoGainControlOnLowAudio \
721 MANUAL_TestAutoGainControlOnLowAudio
722 #else
723 #define MAYBE_MANUAL_TestAutoGainControlOnLowAudio \
724 DISABLED_MANUAL_TestAutoGainControlOnLowAudio
725 #endif
726
727 // The AGC should apply gain here on the order of 5-6 dBFS units.
henrika (OOO until Aug 14) 2014/12/19 10:00:14 How do you know this gain? is it digital only?
phoglund_chromium 2014/12/19 10:34:20 I guess I don't really, but those are the results
728 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioQualityBrowserTest,
729 MAYBE_MANUAL_TestAutoGainControlOnLowAudio) {
730 ASSERT_NO_FATAL_FAILURE(TestAutoGainControl(
731 kAgcTestReferenceFile, kAudioOnlyCallConstraints, "_with_agc"));
732 }
733
734 // Only implemented for Linux for now.
735 #if defined(OS_LINUX)
736 #define MAYBE_MANUAL_TestComputeGainWithAudioProcessingOff \
737 MANUAL_TestComputeGainWithAudioProcessingOff
738 #else
739 #define MAYBE_MANUAL_TestComputeGainWithAudioProcessingOff \
740 DISABLED_MANUAL_TestComputeGainWithAudioProcessingOff
741 #endif
742
743 // Since the AGC is off here there should be no gain at all.
744 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioQualityBrowserTest,
745 MAYBE_MANUAL_TestComputeGainWithAudioProcessingOff) {
746 const char* kAudioCallWithoutAudioProcessing =
747 "{audio: { mandatory: { echoCancellation: false } } }";
748 ASSERT_NO_FATAL_FAILURE(TestAutoGainControl(
749 kAgcTestReferenceFile, kAudioCallWithoutAudioProcessing, "_no_agc"));
750 }
751
OLDNEW
« no previous file with comments | « no previous file | chrome/browser/media/webrtc_browsertest_audio.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698