OLD | NEW |
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_enumerator.h" |
9 #include "base/files/file_util.h" | 9 #include "base/files/file_util.h" |
10 #include "base/files/scoped_temp_dir.h" | 10 #include "base/files/scoped_temp_dir.h" |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
47 #define MAYBE_WebRtcAudioQualityBrowserTest WebRtcAudioQualityBrowserTest | 47 #define MAYBE_WebRtcAudioQualityBrowserTest WebRtcAudioQualityBrowserTest |
48 #else | 48 #else |
49 // Not implemented on Android, ChromeOS etc. | 49 // Not implemented on Android, ChromeOS etc. |
50 #define MAYBE_WebRtcAudioQualityBrowserTest DISABLED_WebRtcAudioQualityBrowserTe
st | 50 #define MAYBE_WebRtcAudioQualityBrowserTest DISABLED_WebRtcAudioQualityBrowserTe
st |
51 #endif | 51 #endif |
52 | 52 |
53 } // namespace | 53 } // namespace |
54 | 54 |
55 // Test we can set up a WebRTC call and play audio through it. | 55 // Test we can set up a WebRTC call and play audio through it. |
56 // | 56 // |
| 57 // WARNING: this test may mess with both output and input levels on your system |
| 58 // and may cause audio to start blasting at full volume into your |
| 59 // headphones. |
| 60 // |
57 // If you're not a googler and want to run this test, you need to provide a | 61 // If you're not a googler and want to run this test, you need to provide a |
58 // pesq binary for your platform (and sox.exe on windows). Read more on how | 62 // pesq binary for your platform (and sox.exe on windows). Read more on how |
59 // resources are managed in chrome/test/data/webrtc/resources/README. | 63 // resources are managed in chrome/test/data/webrtc/resources/README. |
60 // | 64 // |
61 // This test will only work on machines that have been configured to record | 65 // This test will only work on machines that have been configured to record |
62 // their own input. | 66 // their own input. |
63 // | 67 // |
64 // On Linux: | 68 // On Linux: |
65 // 1. # sudo apt-get install pavucontrol sox | 69 // 1. # sudo apt-get install pavucontrol sox |
66 // 2. For the user who will run the test: # pavucontrol | 70 // 2. For the user who will run the test: # pavucontrol |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
99 // 1. Control panel > Sound > Manage audio devices. | 103 // 1. Control panel > Sound > Manage audio devices. |
100 // 2. In the recording tab, right-click in an empty space in the pane with the | 104 // 2. In the recording tab, right-click in an empty space in the pane with the |
101 // devices. Tick 'show disabled devices'. | 105 // devices. Tick 'show disabled devices'. |
102 // 3. You should see a 'stero mix' device - this is what your speakers output. | 106 // 3. You should see a 'stero mix' device - this is what your speakers output. |
103 // Right click > Properties. | 107 // Right click > Properties. |
104 // 4. In the Listen tab for the mix device, check the 'listen to this device' | 108 // 4. In the Listen tab for the mix device, check the 'listen to this device' |
105 // checkbox. Ensure the mix device is the default recording device. | 109 // checkbox. Ensure the mix device is the default recording device. |
106 // 5. Launch chrome and try playing a video with sound. You should see | 110 // 5. Launch chrome and try playing a video with sound. You should see |
107 // in the volume meter for the mix device. Configure the mix device to have | 111 // in the volume meter for the mix device. Configure the mix device to have |
108 // 50 / 100 in level. Also go into the playback tab, right-click Speakers, | 112 // 50 / 100 in level. Also go into the playback tab, right-click Speakers, |
109 // and set that level to 50 / 100. Otherwise you will get distortion in | 113 // and set that level to 50 / 100. Otherwise you might get distortion in |
110 // the recording. | 114 // the recording. |
111 class MAYBE_WebRtcAudioQualityBrowserTest : public WebRtcTestBase { | 115 class MAYBE_WebRtcAudioQualityBrowserTest : public WebRtcTestBase { |
112 public: | 116 public: |
113 MAYBE_WebRtcAudioQualityBrowserTest() {} | 117 MAYBE_WebRtcAudioQualityBrowserTest() {} |
114 void SetUpInProcessBrowserTestFixture() override { | 118 void SetUpInProcessBrowserTestFixture() override { |
115 DetectErrorsInJavaScript(); // Look for errors in our rather complex js. | 119 DetectErrorsInJavaScript(); // Look for errors in our rather complex js. |
116 } | 120 } |
117 | 121 |
118 void SetUpCommandLine(base::CommandLine* command_line) override { | 122 void SetUpCommandLine(base::CommandLine* command_line) override { |
119 EXPECT_FALSE(command_line->HasSwitch( | 123 EXPECT_FALSE(command_line->HasSwitch( |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
242 // Joins the recording program. Returns true on success. | 246 // Joins the recording program. Returns true on success. |
243 bool WaitForRecordingToEnd() { | 247 bool WaitForRecordingToEnd() { |
244 int exit_code = -1; | 248 int exit_code = -1; |
245 recording_application_.WaitForExit(&exit_code); | 249 recording_application_.WaitForExit(&exit_code); |
246 return exit_code == 0; | 250 return exit_code == 0; |
247 } | 251 } |
248 private: | 252 private: |
249 base::Process recording_application_; | 253 base::Process recording_application_; |
250 }; | 254 }; |
251 | 255 |
252 bool ForceMicrophoneVolumeTo100Percent() { | 256 bool ForceMicrophoneLevelTo100Percent() { |
253 #if defined(OS_WIN) | 257 #if defined(OS_WIN) |
254 // Note: the force binary isn't in tools since it's one of our own. | 258 // Note: the force binary isn't in tools since it's one of our own. |
255 base::CommandLine command_line(test::GetReferenceFilesDir().Append( | 259 base::CommandLine command_line(test::GetReferenceFilesDir().Append( |
256 FILE_PATH_LITERAL("force_mic_volume_max.exe"))); | 260 FILE_PATH_LITERAL("force_mic_volume_max.exe"))); |
257 DVLOG(0) << "Running " << command_line.GetCommandLineString(); | 261 DVLOG(0) << "Running " << command_line.GetCommandLineString(); |
258 std::string result; | 262 std::string result; |
259 if (!base::GetAppOutput(command_line, &result)) { | 263 if (!base::GetAppOutput(command_line, &result)) { |
260 LOG(ERROR) << "Failed to set source volume: output was " << result; | 264 LOG(ERROR) << "Failed to set source volume: output was " << result; |
261 return false; | 265 return false; |
262 } | 266 } |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
480 } | 484 } |
481 | 485 |
482 // Splits |to_split| into sub-files based on silence. The file you use must have | 486 // Splits |to_split| into sub-files based on silence. The file you use must have |
483 // at least 500 ms periods of silence between speech segments for this to be | 487 // at least 500 ms periods of silence between speech segments for this to be |
484 // reliable. | 488 // reliable. |
485 void SplitFileOnSilenceIntoDir(const base::FilePath& to_split, | 489 void SplitFileOnSilenceIntoDir(const base::FilePath& to_split, |
486 const base::FilePath& workdir) { | 490 const base::FilePath& workdir) { |
487 // First trim beginning and end since they are tricky for the splitter. | 491 // First trim beginning and end since they are tricky for the splitter. |
488 base::FilePath trimmed_audio = CreateTemporaryWaveFile(); | 492 base::FilePath trimmed_audio = CreateTemporaryWaveFile(); |
489 | 493 |
| 494 // TODO(phoglund): find smarter way to do this and get rid of RemoveSilence. |
490 ASSERT_TRUE(RemoveSilence(to_split, trimmed_audio)); | 495 ASSERT_TRUE(RemoveSilence(to_split, trimmed_audio)); |
491 DVLOG(0) << "Trimmed silence: " << trimmed_audio.value() << std::endl; | 496 DVLOG(0) << "Trimmed silence: " << trimmed_audio.value() << std::endl; |
492 | 497 |
493 ASSERT_TRUE(SplitFileOnSilence( | 498 ASSERT_TRUE(SplitFileOnSilence( |
494 trimmed_audio, workdir.Append(FILE_PATH_LITERAL("output.wav")))); | 499 trimmed_audio, workdir.Append(FILE_PATH_LITERAL("output.wav")))); |
495 ASSERT_TRUE(base::DeleteFile(trimmed_audio, false)); | 500 ASSERT_TRUE(base::DeleteFile(trimmed_audio, false)); |
496 } | 501 } |
497 | 502 |
498 // Computes the difference between the actual and reference segment. A positive | 503 // Computes the difference between the actual and reference segment. A positive |
499 // number x means the actual file is x dB stronger than the reference. | 504 // number x means the actual file is x dB stronger than the reference. |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
536 std::string trace_name = base::StringPrintf( | 541 std::string trace_name = base::StringPrintf( |
537 "%s_segment_%zu", reference_file.BaseName().value().c_str(), i); | 542 "%s_segment_%zu", reference_file.BaseName().value().c_str(), i); |
538 perf_test::PrintResult("agc_energy_diff", perf_modifier, trace_name, | 543 perf_test::PrintResult("agc_energy_diff", perf_modifier, trace_name, |
539 difference_in_decibel, "dB", false); | 544 difference_in_decibel, "dB", false); |
540 } | 545 } |
541 } | 546 } |
542 | 547 |
543 void ComputeAndPrintPesqResults(const base::FilePath& reference_file, | 548 void ComputeAndPrintPesqResults(const base::FilePath& reference_file, |
544 const base::FilePath& recording, | 549 const base::FilePath& recording, |
545 const std::string& perf_modifier) { | 550 const std::string& perf_modifier) { |
546 base::FilePath trimmed_reference = CreateTemporaryWaveFile(); | |
547 base::FilePath trimmed_recording = CreateTemporaryWaveFile(); | |
548 | |
549 ASSERT_TRUE(RemoveSilence(reference_file, trimmed_reference)); | |
550 ASSERT_TRUE(RemoveSilence(recording, trimmed_recording)); | |
551 | |
552 std::string raw_mos; | 551 std::string raw_mos; |
553 std::string mos_lqo; | 552 std::string mos_lqo; |
554 ASSERT_TRUE(RunPesq(trimmed_reference, trimmed_recording, 16000, | 553 ASSERT_TRUE(RunPesq(reference_file, recording, 16000, &raw_mos, &mos_lqo)); |
555 &raw_mos, &mos_lqo)); | |
556 | 554 |
557 perf_test::PrintResult( | 555 perf_test::PrintResult( |
558 "audio_pesq", perf_modifier, "raw_mos", raw_mos, "score", true); | 556 "audio_pesq", perf_modifier, "raw_mos", raw_mos, "score", true); |
559 perf_test::PrintResult( | 557 perf_test::PrintResult( |
560 "audio_pesq", perf_modifier, "mos_lqo", mos_lqo, "score", true); | 558 "audio_pesq", perf_modifier, "mos_lqo", mos_lqo, "score", true); |
561 | |
562 EXPECT_TRUE(base::DeleteFile(trimmed_reference, false)); | |
563 EXPECT_TRUE(base::DeleteFile(trimmed_recording, false)); | |
564 } | 559 } |
565 | 560 |
566 } // namespace | 561 } // namespace |
567 | 562 |
568 // Sets up a one-way WebRTC call and records its output to |recording|, using | 563 // Sets up a one-way WebRTC call and records its output to |recording|, using |
569 // getUserMedia. | 564 // getUserMedia. |
570 // | 565 // |
571 // |reference_file| should have at least two seconds of silence in the | 566 // |reference_file| should have at least two seconds of silence in the |
572 // beginning: otherwise all the reference audio will not be picked up by the | 567 // beginning: otherwise all the reference audio will not be picked up by the |
573 // recording. Note that the reference file will start playing as soon as the | 568 // recording. Note that the reference file will start playing as soon as the |
574 // audio device is up following the getUserMedia call in the left tab. The time | 569 // audio device is up following the getUserMedia call in the left tab. The time |
575 // it takes to negotiate a call isn't deterministic, but two seconds should be | 570 // it takes to negotiate a call isn't deterministic, but two seconds should be |
576 // plenty of time. Similarly, the recording time should be enough to catch the | 571 // plenty of time. Similarly, the recording time should be enough to catch the |
577 // whole reference file. If you then silence-trim the reference file and actual | 572 // whole reference file. |
578 // file, you should end up with two time-synchronized files. | |
579 void MAYBE_WebRtcAudioQualityBrowserTest::SetupAndRecordAudioCall( | 573 void MAYBE_WebRtcAudioQualityBrowserTest::SetupAndRecordAudioCall( |
580 const base::FilePath& reference_file, | 574 const base::FilePath& reference_file, |
581 const base::FilePath& recording, | 575 const base::FilePath& recording, |
582 const std::string& constraints, | 576 const std::string& constraints, |
583 const base::TimeDelta recording_time) { | 577 const base::TimeDelta recording_time) { |
584 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); | 578 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); |
585 ASSERT_TRUE(test::HasReferenceFilesInCheckout()); | 579 ASSERT_TRUE(test::HasReferenceFilesInCheckout()); |
586 ASSERT_TRUE(ForceMicrophoneVolumeTo100Percent()); | 580 ASSERT_TRUE(ForceMicrophoneLevelTo100Percent()); |
587 | 581 |
588 ConfigureFakeDeviceToPlayFile(reference_file); | 582 ConfigureFakeDeviceToPlayFile(reference_file); |
589 | 583 |
590 // Create a one-way call. | 584 // Create a one-way call. |
591 GURL test_page = embedded_test_server()->GetURL(kWebRtcAudioTestHtmlPage); | 585 GURL test_page = embedded_test_server()->GetURL(kWebRtcAudioTestHtmlPage); |
592 content::WebContents* left_tab = | 586 content::WebContents* left_tab = |
593 OpenPageAndGetUserMediaInNewTabWithConstraints(test_page, constraints); | 587 OpenPageAndGetUserMediaInNewTabWithConstraints(test_page, constraints); |
594 SetupPeerconnectionWithLocalStream(left_tab); | 588 SetupPeerconnectionWithLocalStream(left_tab); |
595 | 589 |
596 content::WebContents* right_tab = | 590 content::WebContents* right_tab = |
(...skipping 27 matching lines...) Expand all Loading... |
624 return; | 618 return; |
625 } | 619 } |
626 | 620 |
627 base::FilePath reference_file = | 621 base::FilePath reference_file = |
628 test::GetReferenceFilesDir().Append(kReferenceFile); | 622 test::GetReferenceFilesDir().Append(kReferenceFile); |
629 base::FilePath recording = CreateTemporaryWaveFile(); | 623 base::FilePath recording = CreateTemporaryWaveFile(); |
630 | 624 |
631 ASSERT_NO_FATAL_FAILURE(SetupAndRecordAudioCall( | 625 ASSERT_NO_FATAL_FAILURE(SetupAndRecordAudioCall( |
632 reference_file, recording, kAudioOnlyCallConstraints, | 626 reference_file, recording, kAudioOnlyCallConstraints, |
633 base::TimeDelta::FromSeconds(25))); | 627 base::TimeDelta::FromSeconds(25))); |
634 ComputeAndPrintPesqResults(reference_file, recording, "_getusermedia"); | 628 ASSERT_NO_FATAL_FAILURE(ComputeAndPrintPesqResults( |
| 629 reference_file, recording, "_getusermedia")); |
635 | 630 |
636 EXPECT_TRUE(base::DeleteFile(recording, false)); | 631 EXPECT_TRUE(base::DeleteFile(recording, false)); |
637 } | 632 } |
638 | 633 |
639 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioQualityBrowserTest, | 634 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioQualityBrowserTest, |
640 MANUAL_TestCallQualityWithAudioFromWebAudio) { | 635 MANUAL_TestCallQualityWithAudioFromWebAudio) { |
641 if (OnWinXp() || OnWin8()) { | 636 if (OnWinXp() || OnWin8()) { |
642 // http://crbug.com/379798. | 637 // http://crbug.com/379798. |
643 LOG(ERROR) << "This test is not implemented for Windows XP/Win8."; | 638 LOG(ERROR) << "This test is not implemented for Windows XP/Win8."; |
644 return; | 639 return; |
645 } | 640 } |
646 ASSERT_TRUE(test::HasReferenceFilesInCheckout()); | 641 ASSERT_TRUE(test::HasReferenceFilesInCheckout()); |
647 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); | 642 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); |
648 | 643 |
649 ASSERT_TRUE(ForceMicrophoneVolumeTo100Percent()); | 644 ASSERT_TRUE(ForceMicrophoneLevelTo100Percent()); |
650 | 645 |
651 content::WebContents* left_tab = | 646 content::WebContents* left_tab = |
652 OpenPageWithoutGetUserMedia(kWebRtcAudioTestHtmlPage); | 647 OpenPageWithoutGetUserMedia(kWebRtcAudioTestHtmlPage); |
653 content::WebContents* right_tab = | 648 content::WebContents* right_tab = |
654 OpenPageWithoutGetUserMedia(kWebRtcAudioTestHtmlPage); | 649 OpenPageWithoutGetUserMedia(kWebRtcAudioTestHtmlPage); |
655 | 650 |
656 AddAudioFileToWebAudio(kReferenceFileRelativeUrl, left_tab); | 651 AddAudioFileToWebAudio(kReferenceFileRelativeUrl, left_tab); |
657 | 652 |
658 NegotiateCall(left_tab, right_tab); | 653 NegotiateCall(left_tab, right_tab); |
659 | 654 |
660 base::FilePath recording = CreateTemporaryWaveFile(); | 655 base::FilePath recording = CreateTemporaryWaveFile(); |
661 | 656 |
662 // Note: the sound clip is about 13 seconds: record for 20 seconds to get some | 657 // Note: the sound clip is about 13 seconds: record for 20 seconds to get some |
663 // safety margins on each side. | 658 // safety margins on each side. |
664 AudioRecorder recorder; | 659 AudioRecorder recorder; |
665 ASSERT_TRUE(recorder.StartRecording(base::TimeDelta::FromSeconds(20), | 660 ASSERT_TRUE(recorder.StartRecording(base::TimeDelta::FromSeconds(20), |
666 recording)); | 661 recording)); |
667 | 662 |
668 PlayAudioFileThroughWebAudio(left_tab); | 663 PlayAudioFileThroughWebAudio(left_tab); |
669 | 664 |
670 ASSERT_TRUE(recorder.WaitForRecordingToEnd()); | 665 ASSERT_TRUE(recorder.WaitForRecordingToEnd()); |
671 DVLOG(0) << "Done recording to " << recording.value() << std::endl; | 666 DVLOG(0) << "Done recording to " << recording.value() << std::endl; |
672 | 667 |
673 HangUp(left_tab); | 668 HangUp(left_tab); |
674 | 669 |
675 // Compare with the reference file on disk (this is the same file we played | 670 // Compare with the reference file on disk (this is the same file we played |
676 // through WebAudio earlier). | 671 // through WebAudio earlier). |
677 base::FilePath reference_file = | 672 base::FilePath reference_file = |
678 test::GetReferenceFilesDir().Append(kReferenceFile); | 673 test::GetReferenceFilesDir().Append(kReferenceFile); |
679 ComputeAndPrintPesqResults(reference_file, recording, "_webaudio"); | 674 ASSERT_NO_FATAL_FAILURE(ComputeAndPrintPesqResults( |
| 675 reference_file, recording, "_webaudio")); |
| 676 EXPECT_TRUE(base::DeleteFile(recording, false)); |
680 } | 677 } |
681 | 678 |
682 /** | 679 /** |
683 * The auto gain control test plays a file into the fake microphone. Then it | 680 * The auto gain control test plays a file into the fake microphone. Then it |
684 * sets up a one-way WebRTC call with audio only and records Chrome's output on | 681 * sets up a one-way WebRTC call with audio only and records Chrome's output on |
685 * the receiving side using the audio loopback provided by the quality test | 682 * the receiving side using the audio loopback provided by the quality test |
686 * (see the class comments for more details). | 683 * (see the class comments for more details). |
687 * | 684 * |
688 * Then both the recording and reference file are split on silence. This creates | 685 * Then both the recording and reference file are split on silence. This creates |
689 * a number of segments with speech in them. The reason for this is to provide | 686 * a number of segments with speech in them. The reason for this is to provide |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
774 #endif | 771 #endif |
775 | 772 |
776 // Since the AGC is off here there should be no gain at all. | 773 // Since the AGC is off here there should be no gain at all. |
777 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioQualityBrowserTest, | 774 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioQualityBrowserTest, |
778 MAYBE_MANUAL_TestAutoGainIsOffWithAudioProcessingOff) { | 775 MAYBE_MANUAL_TestAutoGainIsOffWithAudioProcessingOff) { |
779 const char* kAudioCallWithoutAudioProcessing = | 776 const char* kAudioCallWithoutAudioProcessing = |
780 "{audio: { mandatory: { echoCancellation: false } } }"; | 777 "{audio: { mandatory: { echoCancellation: false } } }"; |
781 ASSERT_NO_FATAL_FAILURE(TestAutoGainControl( | 778 ASSERT_NO_FATAL_FAILURE(TestAutoGainControl( |
782 kReferenceFile, kAudioCallWithoutAudioProcessing, "_no_agc")); | 779 kReferenceFile, kAudioCallWithoutAudioProcessing, "_no_agc")); |
783 } | 780 } |
OLD | NEW |