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

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

Issue 831693004: Added WebRTC audio quality test using fake device; improved fake device (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 11 months 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/test/data/webrtc/resources/human-voice-linux.wav.sha1 » ('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_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 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
165 // getUserMedia-derived media streams in this test like the other tests. 165 // getUserMedia-derived media streams in this test like the other tests.
166 EXPECT_EQ("ok-peerconnection-created", 166 EXPECT_EQ("ok-peerconnection-created",
167 ExecuteJavascript("preparePeerConnection()", tab)); 167 ExecuteJavascript("preparePeerConnection()", tab));
168 return tab; 168 return tab;
169 } 169 }
170 170
171 protected: 171 protected:
172 void TestAutoGainControl(const base::FilePath::StringType& reference_filename, 172 void TestAutoGainControl(const base::FilePath::StringType& reference_filename,
173 const std::string& constraints, 173 const std::string& constraints,
174 const std::string& perf_modifier); 174 const std::string& perf_modifier);
175 void SetupAndRecordAudioCall(const base::FilePath& reference_file,
176 const base::FilePath& recording,
177 const std::string& constraints,
178 const base::TimeDelta recording_time);
175 }; 179 };
176 180
177 namespace { 181 namespace {
178 182
179 class AudioRecorder { 183 class AudioRecorder {
180 public: 184 public:
181 AudioRecorder() {} 185 AudioRecorder() {}
182 ~AudioRecorder() {} 186 ~AudioRecorder() {}
183 187
184 // Starts the recording program for the specified duration. Returns true 188 // Starts the recording program for the specified duration. Returns true
185 // on success. We record in 44.1 kHz 16-bit format unless |record_cd| is 189 // on success. We record in 44.1 kHz 16-bit format unless |record_cd| is
186 // false, in which case we record in 48 kHz 16-bit format. We record in stereo 190 // false, in which case we record in 48 kHz 16-bit format. We record in stereo
187 // unless |mono| is true. 191 // unless |mono| is true.
188 // TODO(phoglund): make win and mac also support the record_cd parameter. Or, 192 // TODO(phoglund): make win and mac also support the record_cd parameter. Or,
189 // even better, make everybody use the CD format rather than DAT. 193 // even better, make everybody use the CD format rather than DAT.
190 bool StartRecording(int duration_sec, const base::FilePath& output_file, 194 bool StartRecording(base::TimeDelta recording_time,
191 bool mono, bool record_cd) { 195 const base::FilePath& output_file, bool mono,
196 bool record_cd) {
192 EXPECT_FALSE(recording_application_.IsValid()) 197 EXPECT_FALSE(recording_application_.IsValid())
193 << "Tried to record, but is already recording."; 198 << "Tried to record, but is already recording.";
194 199
200 int duration_sec = static_cast<int>(recording_time.InSeconds());
195 base::CommandLine command_line(base::CommandLine::NO_PROGRAM); 201 base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
202
196 #if defined(OS_WIN) 203 #if defined(OS_WIN)
197 // This disable is required to run SoundRecorder.exe on 64-bit Windows 204 // This disable is required to run SoundRecorder.exe on 64-bit Windows
198 // from a 32-bit binary. We need to load the wow64 disable function from 205 // from a 32-bit binary. We need to load the wow64 disable function from
199 // the DLL since it doesn't exist on Windows XP. 206 // the DLL since it doesn't exist on Windows XP.
200 // TODO(phoglund): find some cleaner solution than using SoundRecorder.exe.
201 base::ScopedNativeLibrary kernel32_lib(base::FilePath(L"kernel32")); 207 base::ScopedNativeLibrary kernel32_lib(base::FilePath(L"kernel32"));
202 if (kernel32_lib.is_valid()) { 208 if (kernel32_lib.is_valid()) {
203 typedef BOOL (WINAPI* Wow64DisableWow64FSRedirection)(PVOID*); 209 typedef BOOL (WINAPI* Wow64DisableWow64FSRedirection)(PVOID*);
204 Wow64DisableWow64FSRedirection wow_64_disable_wow_64_fs_redirection; 210 Wow64DisableWow64FSRedirection wow_64_disable_wow_64_fs_redirection;
205 wow_64_disable_wow_64_fs_redirection = 211 wow_64_disable_wow_64_fs_redirection =
206 reinterpret_cast<Wow64DisableWow64FSRedirection>( 212 reinterpret_cast<Wow64DisableWow64FSRedirection>(
207 kernel32_lib.GetFunctionPointer( 213 kernel32_lib.GetFunctionPointer(
208 "Wow64DisableWow64FsRedirection")); 214 "Wow64DisableWow64FsRedirection"));
209 if (wow_64_disable_wow_64_fs_redirection != NULL) { 215 if (wow_64_disable_wow_64_fs_redirection != NULL) {
210 PVOID* ignored = NULL; 216 PVOID* ignored = NULL;
(...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after
554 float difference_in_decibel = AnalyzeOneSegment(ref_segments[i], 560 float difference_in_decibel = AnalyzeOneSegment(ref_segments[i],
555 actual_segments[i], 561 actual_segments[i],
556 i); 562 i);
557 std::string trace_name = base::StringPrintf( 563 std::string trace_name = base::StringPrintf(
558 "%s_segment_%zu", reference_file.BaseName().value().c_str(), i); 564 "%s_segment_%zu", reference_file.BaseName().value().c_str(), i);
559 perf_test::PrintResult("agc_energy_diff", perf_modifier, trace_name, 565 perf_test::PrintResult("agc_energy_diff", perf_modifier, trace_name,
560 difference_in_decibel, "dB", false); 566 difference_in_decibel, "dB", false);
561 } 567 }
562 } 568 }
563 569
570 void ComputeAndPrintPesqResults(const base::FilePath& reference_file,
571 const base::FilePath& recording,
572 const std::string& perf_modifier) {
573 base::FilePath trimmed_reference = CreateTemporaryWaveFile();
574 base::FilePath trimmed_recording = CreateTemporaryWaveFile();
575
576 ASSERT_TRUE(RemoveSilence(recording, trimmed_reference));
577 ASSERT_TRUE(RemoveSilence(recording, trimmed_recording));
578
579 std::string raw_mos;
580 std::string mos_lqo;
581 ASSERT_TRUE(RunPesq(trimmed_reference, trimmed_recording, 16000,
582 &raw_mos, &mos_lqo));
583
584 perf_test::PrintResult(
585 "audio_pesq", perf_modifier, "raw_mos", raw_mos, "score", true);
586 perf_test::PrintResult(
587 "audio_pesq", perf_modifier, "mos_lqo", mos_lqo, "score", true);
588
589 EXPECT_TRUE(base::DeleteFile(trimmed_reference, false));
590 EXPECT_TRUE(base::DeleteFile(trimmed_recording, false));
591 }
592
564 } // namespace 593 } // namespace
565 594
595 // Sets up a one-way WebRTC call and records its output to |recording|, using
596 // getUserMedia.
597 //
598 // |reference_file| should have at least two seconds of silence in the
599 // beginning: otherwise all the reference audio will not be picked up by the
600 // recording. Note that the reference file will start playing as soon as the
601 // audio device is up following the getUserMedia call in the left tab. The time
602 // it takes to negotiate a call isn't deterministic, but two seconds should be
603 // plenty of time. Similarly, the recording time should be enough to catch the
604 // whole reference file. If you then silence-trim the reference file and actual
605 // file, you should end up with two time-synchronized files.
606 void MAYBE_WebRtcAudioQualityBrowserTest::SetupAndRecordAudioCall(
607 const base::FilePath& reference_file,
608 const base::FilePath& recording,
609 const std::string& constraints,
610 const base::TimeDelta recording_time) {
611 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
612 ASSERT_TRUE(test::HasReferenceFilesInCheckout());
613 ASSERT_TRUE(ForceMicrophoneVolumeTo100Percent());
614
615 ConfigureFakeDeviceToPlayFile(reference_file);
616
617 // Create a one-way call.
618 GURL test_page = embedded_test_server()->GetURL(kWebRtcAudioTestHtmlPage);
619 content::WebContents* left_tab =
620 OpenPageAndGetUserMediaInNewTabWithConstraints(test_page, constraints);
621 SetupPeerconnectionWithLocalStream(left_tab);
622
623 content::WebContents* right_tab =
624 OpenPageWithoutGetUserMedia(kWebRtcAudioTestHtmlPage);
625
626 AudioRecorder recorder;
627 ASSERT_TRUE(recorder.StartRecording(recording_time, recording, false, true));
628
629 NegotiateCall(left_tab, right_tab);
630
631 ASSERT_TRUE(recorder.WaitForRecordingToEnd());
632 DVLOG(0) << "Done recording to " << recording.value() << std::endl;
633
634 HangUp(left_tab);
635 }
636
566 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioQualityBrowserTest, 637 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioQualityBrowserTest,
567 MANUAL_TestAudioQuality) { 638 MANUAL_TestCallQualityWithAudioFromFakeDevice) {
568 if (OnWinXp()) { 639 if (OnWinXp() || OnWin8()) {
569 LOG(ERROR) << "This test is not implemented for Windows XP."; 640 // http://crbug.com/379798.
641 LOG(ERROR) << "This test is not implemented for Windows XP/Win8.";
570 return; 642 return;
571 } 643 }
572 if (OnWin8()) { 644
645 base::FilePath reference_file =
646 test::GetReferenceFilesDir().Append(kReferenceFile);
647 base::FilePath recording = CreateTemporaryWaveFile();
648
649 ASSERT_NO_FATAL_FAILURE(SetupAndRecordAudioCall(
650 reference_file, recording, kAudioOnlyCallConstraints,
651 base::TimeDelta::FromSeconds(25)));
652 ComputeAndPrintPesqResults(reference_file, recording, "_getusermedia");
653
654 EXPECT_TRUE(base::DeleteFile(recording, false));
655 }
656
657 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioQualityBrowserTest,
658 MANUAL_TestCallQualityWithAudioFromWebAudio) {
659 if (OnWinXp() || OnWin8()) {
573 // http://crbug.com/379798. 660 // http://crbug.com/379798.
574 LOG(ERROR) << "Temporarily disabled for Win 8."; 661 LOG(ERROR) << "This test is not implemented for Windows XP/Win8.";
575 return; 662 return;
576 } 663 }
577 ASSERT_TRUE(test::HasReferenceFilesInCheckout()); 664 ASSERT_TRUE(test::HasReferenceFilesInCheckout());
578 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 665 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
579 666
580 ASSERT_TRUE(ForceMicrophoneVolumeTo100Percent()); 667 ASSERT_TRUE(ForceMicrophoneVolumeTo100Percent());
581 668
582 content::WebContents* left_tab = 669 content::WebContents* left_tab =
583 OpenPageWithoutGetUserMedia(kWebRtcAudioTestHtmlPage); 670 OpenPageWithoutGetUserMedia(kWebRtcAudioTestHtmlPage);
584 content::WebContents* right_tab = 671 content::WebContents* right_tab =
585 OpenPageWithoutGetUserMedia(kWebRtcAudioTestHtmlPage); 672 OpenPageWithoutGetUserMedia(kWebRtcAudioTestHtmlPage);
586 673
587 AddAudioFileToWebAudio(kReferenceFileRelativeUrl, left_tab); 674 AddAudioFileToWebAudio(kReferenceFileRelativeUrl, left_tab);
588 675
589 NegotiateCall(left_tab, right_tab); 676 NegotiateCall(left_tab, right_tab);
590 677
591 // Note: the media flow isn't necessarily established on the connection just
592 // because the ready state is ok on both sides. We sleep a bit between call
593 // establishment and playing to avoid cutting off the beginning of the stream.
594 test::SleepInJavascript(left_tab, 2000);
595
596 base::FilePath recording = CreateTemporaryWaveFile(); 678 base::FilePath recording = CreateTemporaryWaveFile();
597 679
598 // Note: the sound clip is about 10 seconds: record for 15 seconds to get some 680 // Note: the sound clip is about 13 seconds: record for 20 seconds to get some
phoglund_chromium 2015/01/07 15:16:26 This is because I added 3 seconds of silence to th
599 // safety margins on each side. 681 // safety margins on each side.
600 AudioRecorder recorder; 682 AudioRecorder recorder;
601 static int kRecordingTimeSeconds = 15; 683 ASSERT_TRUE(recorder.StartRecording(base::TimeDelta::FromSeconds(20),
602 ASSERT_TRUE(recorder.StartRecording(kRecordingTimeSeconds, recording, 684 recording, true, false));
603 true, false));
604 685
605 PlayAudioFileThroughWebAudio(left_tab); 686 PlayAudioFileThroughWebAudio(left_tab);
606 687
607 ASSERT_TRUE(recorder.WaitForRecordingToEnd()); 688 ASSERT_TRUE(recorder.WaitForRecordingToEnd());
608 DVLOG(0) << "Done recording to " << recording.value() << std::endl; 689 DVLOG(0) << "Done recording to " << recording.value() << std::endl;
609 690
610 HangUp(left_tab); 691 HangUp(left_tab);
611 692
612 base::FilePath trimmed_recording = CreateTemporaryWaveFile(); 693 // Compare with the reference file on disk (this is the same file we played
613 694 // through WebAudio earlier).
614 ASSERT_TRUE(RemoveSilence(recording, trimmed_recording)); 695 base::FilePath reference_file =
615 DVLOG(0) << "Trimmed silence: " << trimmed_recording.value() << std::endl;
616
617 std::string raw_mos;
618 std::string mos_lqo;
619 base::FilePath reference_file_in_test_dir =
620 test::GetReferenceFilesDir().Append(kReferenceFile); 696 test::GetReferenceFilesDir().Append(kReferenceFile);
621 ASSERT_TRUE(RunPesq(reference_file_in_test_dir, trimmed_recording, 16000, 697 ComputeAndPrintPesqResults(reference_file, recording, "_webaudio");
622 &raw_mos, &mos_lqo));
623
624 perf_test::PrintResult("audio_pesq", "", "raw_mos", raw_mos, "score", true);
625 perf_test::PrintResult("audio_pesq", "", "mos_lqo", mos_lqo, "score", true);
626
627 EXPECT_TRUE(base::DeleteFile(recording, false));
628 EXPECT_TRUE(base::DeleteFile(trimmed_recording, false));
629 } 698 }
630 699
631 /** 700 /**
632 * The auto gain control test plays a file into the fake microphone. Then it 701 * The auto gain control test plays a file into the fake microphone. Then it
633 * sets up a one-way WebRTC call with audio only and records Chrome's output on 702 * sets up a one-way WebRTC call with audio only and records Chrome's output on
634 * the receiving side using the audio loopback provided by the quality test 703 * the receiving side using the audio loopback provided by the quality test
635 * (see the class comments for more details). 704 * (see the class comments for more details).
636 * 705 *
637 * Then both the recording and reference file are split on silence. This creates 706 * Then both the recording and reference file are split on silence. This creates
638 * a number of segments with speech in them. The reason for this is to provide 707 * a number of segments with speech in them. The reason for this is to provide
(...skipping 16 matching lines...) Expand all
655 * The test only exercises digital AGC for now. 724 * The test only exercises digital AGC for now.
656 * 725 *
657 * We record in CD format here (44.1 kHz) because that's what the fake input 726 * We record in CD format here (44.1 kHz) because that's what the fake input
658 * device currently supports, and we want to be able to compare directly. See 727 * device currently supports, and we want to be able to compare directly. See
659 * http://crbug.com/421054. 728 * http://crbug.com/421054.
660 */ 729 */
661 void MAYBE_WebRtcAudioQualityBrowserTest::TestAutoGainControl( 730 void MAYBE_WebRtcAudioQualityBrowserTest::TestAutoGainControl(
662 const base::FilePath::StringType& reference_filename, 731 const base::FilePath::StringType& reference_filename,
663 const std::string& constraints, 732 const std::string& constraints,
664 const std::string& perf_modifier) { 733 const std::string& perf_modifier) {
665 if (OnWinXp()) { 734 if (OnWinXp() || OnWin8()) {
666 LOG(ERROR) << "This test is not implemented for Windows XP."; 735 // http://crbug.com/379798.
736 LOG(ERROR) << "This test is not implemented for Windows XP/Win8.";
667 return; 737 return;
668 } 738 }
669 if (OnWin8()) {
670 // http://crbug.com/379798.
671 LOG(ERROR) << "Temporarily disabled for Win 8.";
672 return;
673 }
674 ASSERT_TRUE(test::HasReferenceFilesInCheckout());
675 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
676
677 ASSERT_TRUE(ForceMicrophoneVolumeTo100Percent());
678
679 base::FilePath reference_file = 739 base::FilePath reference_file =
680 test::GetReferenceFilesDir().Append(reference_filename); 740 test::GetReferenceFilesDir().Append(reference_filename);
681 ConfigureFakeDeviceToPlayFile(reference_file);
682
683 // Create a one-way call.
684 GURL test_page = embedded_test_server()->GetURL(kWebRtcAudioTestHtmlPage);
685 content::WebContents* left_tab =
686 OpenPageAndGetUserMediaInNewTabWithConstraints(test_page, constraints);
687 SetupPeerconnectionWithLocalStream(left_tab);
688
689 content::WebContents* right_tab =
690 OpenPageWithoutGetUserMedia(kWebRtcAudioTestHtmlPage);
691
692 base::FilePath recording = CreateTemporaryWaveFile(); 741 base::FilePath recording = CreateTemporaryWaveFile();
693 742
694 AudioRecorder recorder; 743 ASSERT_NO_FATAL_FAILURE(SetupAndRecordAudioCall(
695 static int kRecordingTimeSeconds = 25; 744 reference_file, recording, constraints,
696 ASSERT_TRUE(recorder.StartRecording(kRecordingTimeSeconds, recording, false, 745 base::TimeDelta::FromSeconds(25)));
697 true));
698
699 NegotiateCall(left_tab, right_tab);
700
701 ASSERT_TRUE(recorder.WaitForRecordingToEnd());
702 DVLOG(0) << "Done recording to " << recording.value() << std::endl;
703
704 HangUp(left_tab);
705 746
706 // Call Take() on the scoped temp dirs if you want to look at the files after 747 // Call Take() on the scoped temp dirs if you want to look at the files after
707 // the test exits (the default is to delete the files). 748 // the test exits (the default is to delete the files).
708 base::ScopedTempDir split_ref_files; 749 base::ScopedTempDir split_ref_files;
709 ASSERT_TRUE(split_ref_files.CreateUniqueTempDir()); 750 ASSERT_TRUE(split_ref_files.CreateUniqueTempDir());
710 ASSERT_NO_FATAL_FAILURE( 751 ASSERT_NO_FATAL_FAILURE(
711 SplitFileOnSilenceIntoDir(reference_file, split_ref_files.path())); 752 SplitFileOnSilenceIntoDir(reference_file, split_ref_files.path()));
712 std::vector<base::FilePath> ref_segments = 753 std::vector<base::FilePath> ref_segments =
713 ListWavFilesInDir(split_ref_files.path()); 754 ListWavFilesInDir(split_ref_files.path());
714 755
(...skipping 21 matching lines...) Expand all
736 777
737 // The AGC should apply non-zero gain here. 778 // The AGC should apply non-zero gain here.
738 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioQualityBrowserTest, 779 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioQualityBrowserTest,
739 MAYBE_MANUAL_TestAutoGainControlOnLowAudio) { 780 MAYBE_MANUAL_TestAutoGainControlOnLowAudio) {
740 ASSERT_NO_FATAL_FAILURE(TestAutoGainControl( 781 ASSERT_NO_FATAL_FAILURE(TestAutoGainControl(
741 kAgcTestReferenceFile, kAudioOnlyCallConstraints, "_with_agc")); 782 kAgcTestReferenceFile, kAudioOnlyCallConstraints, "_with_agc"));
742 } 783 }
743 784
744 // Only implemented for Linux for now. 785 // Only implemented for Linux for now.
745 #if defined(OS_LINUX) 786 #if defined(OS_LINUX)
746 #define MAYBE_MANUAL_TestComputeGainWithAudioProcessingOff \ 787 #define MAYBE_MANUAL_TestAutoGainIsOffWithAudioProcessingOff \
747 MANUAL_TestComputeGainWithAudioProcessingOff 788 MANUAL_TestAutoGainIsOffWithAudioProcessingOff
748 #else 789 #else
749 #define MAYBE_MANUAL_TestComputeGainWithAudioProcessingOff \ 790 #define MAYBE_MANUAL_TestAutoGainIsOffWithAudioProcessingOff \
750 DISABLED_MANUAL_TestComputeGainWithAudioProcessingOff 791 DISABLED_MANUAL_TestAutoGainIsOffWithAudioProcessingOff
751 #endif 792 #endif
752 793
753 // Since the AGC is off here there should be no gain at all. 794 // Since the AGC is off here there should be no gain at all.
754 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioQualityBrowserTest, 795 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioQualityBrowserTest,
755 MAYBE_MANUAL_TestComputeGainWithAudioProcessingOff) { 796 MAYBE_MANUAL_TestAutoGainIsOffWithAudioProcessingOff) {
756 const char* kAudioCallWithoutAudioProcessing = 797 const char* kAudioCallWithoutAudioProcessing =
757 "{audio: { mandatory: { echoCancellation: false } } }"; 798 "{audio: { mandatory: { echoCancellation: false } } }";
758 ASSERT_NO_FATAL_FAILURE(TestAutoGainControl( 799 ASSERT_NO_FATAL_FAILURE(TestAutoGainControl(
759 kAgcTestReferenceFile, kAudioCallWithoutAudioProcessing, "_no_agc")); 800 kAgcTestReferenceFile, kAudioCallWithoutAudioProcessing, "_no_agc"));
760 } 801 }
761
OLDNEW
« no previous file with comments | « no previous file | chrome/test/data/webrtc/resources/human-voice-linux.wav.sha1 » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698