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

Unified Diff: chrome/browser/media/webrtc/webrtc_audio_quality_browsertest.cc

Issue 2753543010: WebRTC: Use the MediaStream Recording API for the audio_quality_browsertest. (Closed)
Patch Set: Addressed comments. Created 3 years, 9 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | chrome/test/data/webrtc/audio_extraction.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/media/webrtc/webrtc_audio_quality_browsertest.cc
diff --git a/chrome/browser/media/webrtc/webrtc_audio_quality_browsertest.cc b/chrome/browser/media/webrtc/webrtc_audio_quality_browsertest.cc
index 8107494b852a4fe7df29dbdfdbec0877ab1eee6a..2995fa3dafa4a584c62030f35421e5277de6c054 100644
--- a/chrome/browser/media/webrtc/webrtc_audio_quality_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_audio_quality_browsertest.cc
@@ -6,6 +6,7 @@
#include <ctime>
+#include "base/base64.h"
#include "base/command_line.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
@@ -50,6 +51,9 @@ static const char kReferenceFileRelativeUrl[] =
static const char kWebRtcAudioTestHtmlPage[] =
"/webrtc/webrtc_audio_quality_test.html";
+// How often to ask the test page whether the audio recording is completed.
+const int kPollingIntervalInMs = 1000;
+
// For the AGC test, there are 6 speech segments split on silence. If one
// segment is significantly different in length compared to the same segment in
// the reference file, there's something fishy going on.
@@ -80,19 +84,8 @@ const int kMaxAgcSegmentDiffMs =
// their own input.
//
// On Linux:
-// 1. # sudo apt-get install pavucontrol sox
+// 1. # sudo apt-get install sox
// 2. For the user who will run the test: # pavucontrol
-// 3. In a separate terminal, # arecord dummy
-// 4. In pavucontrol, go to the recording tab.
-// 5. For the ALSA plugin [aplay]: ALSA Capture from, change from <x> to
-// <Monitor of x>, where x is whatever your primary sound device is called.
-// 6. Try launching chrome as the target user on the target machine, try
-// playing, say, a YouTube video, and record with # arecord -f dat tmp.dat.
-// Verify the recording with aplay (should have recorded what you played
-// from chrome).
-//
-// Note: the volume for ALL your input devices will be forced to 100% by
-// running this test on Linux.
//
// On Mac:
// TODO(phoglund): download sox from gs instead.
@@ -100,35 +93,11 @@ const int kMaxAgcSegmentDiffMs =
// 2. Install it + reboot.
// 3. Install MacPorts (http://www.macports.org/).
// 4. Install sox: sudo port install sox.
-// 5. (For Chrome bots) Ensure sox and rec are reachable from the env the test
+// 5. (For Chrome bots) Ensure sox is reachable from the env the test
// executes in (sox and rec tends to install in /opt/, which generally isn't
// in the Chrome bots' env). For instance, run
// sudo ln -s /opt/local/bin/rec /usr/local/bin/rec
kjellander_chromium 2017/03/21 14:07:26 Remove this line too :)
// sudo ln -s /opt/local/bin/sox /usr/local/bin/sox
-// 6. In Sound Preferences, set both input and output to Soundflower (2ch).
-// Note: You will no longer hear audio on this machine, and it will no
-// longer use any built-in mics.
-// 7. Try launching chrome as the target user on the target machine, try
-// playing, say, a YouTube video, and record with 'rec test.wav trim 0 5'.
-// Stop the video in chrome and try playing back the file; you should hear
-// a recording of the video (note; if you play back on the target machine
-// you must revert the changes in step 3 first).
-//
-// On Windows 7:
-// 1. Control panel > Sound > Manage audio devices.
-// 2. In the recording tab, right-click in an empty space in the pane with the
-// devices. Tick 'show disabled devices'.
-// 3. You should see a 'stereo mix' device - this is what your speakers output.
-// If you don't have one, your driver doesn't support stereo mix devices.
-// Some drivers use different names for the mix device though (like "Wave").
-// Right click > Properties.
-// 4. Ensure "listen to this device" is unchecked, otherwise you get echo.
-// 5. Ensure the mix device is the default recording device.
-// 6. Launch chrome and try playing a video with sound. You should see
-// in the volume meter for the mix device. Configure the mix device to have
-// 50 / 100 in level. Also go into the playback tab, right-click Speakers,
-// and set that level to 50 / 100. Otherwise you will get distortion in
-// the recording.
class MAYBE_WebRtcAudioQualityBrowserTest : public WebRtcTestBase {
public:
MAYBE_WebRtcAudioQualityBrowserTest() {}
@@ -186,147 +155,22 @@ class MAYBE_WebRtcAudioQualityBrowserTest : public WebRtcTestBase {
"setMediaElementMuted('" + element_id + "', true)", tab_contents));
}
+ void WriteCapturedAudio(content::WebContents* capturing_tab,
+ const base::FilePath& audio_filename);
+
protected:
void TestAutoGainControl(const base::FilePath::StringType& reference_filename,
const std::string& constraints,
const std::string& perf_modifier);
void SetupAndRecordAudioCall(const base::FilePath& reference_file,
const base::FilePath& recording,
- const std::string& constraints,
- const base::TimeDelta recording_time);
+ const std::string& constraints);
void TestWithFakeDeviceGetUserMedia(const std::string& constraints,
const std::string& perf_modifier);
};
namespace {
-class AudioRecorder {
- public:
- AudioRecorder() {}
- ~AudioRecorder() {}
-
- // Starts the recording program for the specified duration. Returns true
- // on success. We record in 16-bit 44.1 kHz Stereo (mostly because that's
- // what SoundRecorder.exe will give us and we can't change that).
- bool StartRecording(base::TimeDelta recording_time,
- const base::FilePath& output_file) {
- EXPECT_FALSE(recording_application_.IsValid())
- << "Tried to record, but is already recording.";
-
- int duration_sec = static_cast<int>(recording_time.InSeconds());
- base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
-
-#if defined(OS_WIN)
- // This disable is required to run SoundRecorder.exe on 64-bit Windows
- // from a 32-bit binary. We need to load the wow64 disable function from
- // the DLL since it doesn't exist on Windows XP.
- base::ScopedNativeLibrary kernel32_lib(base::FilePath(L"kernel32"));
- if (kernel32_lib.is_valid()) {
- typedef BOOL (WINAPI* Wow64DisableWow64FSRedirection)(PVOID*);
- Wow64DisableWow64FSRedirection wow_64_disable_wow_64_fs_redirection;
- wow_64_disable_wow_64_fs_redirection =
- reinterpret_cast<Wow64DisableWow64FSRedirection>(
- kernel32_lib.GetFunctionPointer(
- "Wow64DisableWow64FsRedirection"));
- if (wow_64_disable_wow_64_fs_redirection != NULL) {
- PVOID* ignored = NULL;
- wow_64_disable_wow_64_fs_redirection(ignored);
- }
- }
-
- char duration_in_hms[128] = {0};
- struct tm duration_tm = {0};
- duration_tm.tm_sec = duration_sec;
- EXPECT_NE(0u, strftime(duration_in_hms, arraysize(duration_in_hms),
- "%H:%M:%S", &duration_tm));
-
- command_line.SetProgram(
- base::FilePath(FILE_PATH_LITERAL("SoundRecorder.exe")));
- command_line.AppendArg("/FILE");
- command_line.AppendArgPath(output_file);
- command_line.AppendArg("/DURATION");
- command_line.AppendArg(duration_in_hms);
-#elif defined(OS_MACOSX)
- command_line.SetProgram(base::FilePath("rec"));
- command_line.AppendArg("-b");
- command_line.AppendArg("16");
- command_line.AppendArg("-q");
- command_line.AppendArgPath(output_file);
- command_line.AppendArg("trim");
- command_line.AppendArg("0");
- command_line.AppendArg(base::IntToString(duration_sec));
-#else
- command_line.SetProgram(base::FilePath("arecord"));
- command_line.AppendArg("-d");
- command_line.AppendArg(base::IntToString(duration_sec));
- command_line.AppendArg("-f");
- command_line.AppendArg("cd");
- command_line.AppendArg("-c");
- command_line.AppendArg("2");
- command_line.AppendArgPath(output_file);
-#endif
-
- DVLOG(0) << "Running " << command_line.GetCommandLineString();
- recording_application_ =
- base::LaunchProcess(command_line, base::LaunchOptions());
- return recording_application_.IsValid();
- }
-
- // Joins the recording program. Returns true on success.
- bool WaitForRecordingToEnd() {
- int exit_code = -1;
- recording_application_.WaitForExit(&exit_code);
- return exit_code == 0;
- }
- private:
- base::Process recording_application_;
-};
-
-bool ForceMicrophoneVolumeTo100Percent() {
-#if defined(OS_WIN)
- // Note: the force binary isn't in tools since it's one of our own.
- base::CommandLine command_line(test::GetReferenceFilesDir().Append(
- FILE_PATH_LITERAL("force_mic_volume_max.exe")));
- DVLOG(0) << "Running " << command_line.GetCommandLineString();
- std::string result;
- if (!base::GetAppOutput(command_line, &result)) {
- LOG(ERROR) << "Failed to set source volume: output was " << result;
- return false;
- }
-#elif defined(OS_MACOSX)
- base::CommandLine command_line(
- base::FilePath(FILE_PATH_LITERAL("osascript")));
- command_line.AppendArg("-e");
- command_line.AppendArg("set volume input volume 100");
- command_line.AppendArg("-e");
- command_line.AppendArg("set volume output volume 85");
-
- std::string result;
- if (!base::GetAppOutput(command_line, &result)) {
- LOG(ERROR) << "Failed to set source volume: output was " << result;
- return false;
- }
-#else
- // Just force the volume of, say the first 5 devices. A machine will rarely
- // have more input sources than that. This is way easier than finding the
- // input device we happen to be using.
- for (int device_index = 0; device_index < 5; ++device_index) {
- std::string result;
- const std::string kHundredPercentVolume = "65536";
- base::CommandLine command_line(base::FilePath(FILE_PATH_LITERAL("pacmd")));
- command_line.AppendArg("set-source-volume");
- command_line.AppendArg(base::IntToString(device_index));
- command_line.AppendArg(kHundredPercentVolume);
- DVLOG(0) << "Running " << command_line.GetCommandLineString();
- if (!base::GetAppOutput(command_line, &result)) {
- LOG(ERROR) << "Failed to set source volume: output was " << result;
- return false;
- }
- }
-#endif
- return true;
-}
-
// Sox is the "Swiss army knife" of audio processing. We mainly use it for
// silence trimming. See http://sox.sourceforge.net.
base::CommandLine MakeSoxCommandLine() {
@@ -387,6 +231,34 @@ bool RemoveSilence(const base::FilePath& input_file,
return ok;
}
+// Runs ffmpeg on the captured webm video and writes it to a .wav file.
+bool RunWebmToWavConverter(const base::FilePath& webm_audio_filename,
+ const base::FilePath& wav_audio_filename) {
+ base::FilePath path_to_ffmpeg = test::GetToolForPlatform("ffmpeg");
+ if (!base::PathExists(path_to_ffmpeg)) {
+ LOG(ERROR) << "Missing ffmpeg: should be in " << path_to_ffmpeg.value();
+ return false;
+ }
+
+ // Set up ffmpeg to output at a certain bitrate (-ab). This is hopefully set
+ // high enough to avoid degrading audio quality too much.
+ base::CommandLine ffmpeg_command(path_to_ffmpeg);
+ ffmpeg_command.AppendArg("-i");
+ ffmpeg_command.AppendArgPath(webm_audio_filename);
+ ffmpeg_command.AppendArg("-ab");
+ ffmpeg_command.AppendArg("300k");
+ ffmpeg_command.AppendArg("-y");
+ ffmpeg_command.AppendArgPath(wav_audio_filename);
+
+ // We produce an output file that will later be used as an input to the
+ // barcode decoder and frame analyzer tools.
+ DVLOG(0) << "Running " << ffmpeg_command.GetCommandLineString();
+ std::string result;
+ bool ok = base::GetAppOutputAndError(ffmpeg_command, &result);
+ DVLOG(0) << "Output was:\n\n" << result;
+ return ok;
+}
+
// Looks for 0.2 second audio segments surrounded by silences under 0.3% audio
// power and splits the input file on those silences. Output files are written
// according to the output file template (e.g. /tmp/out.wav writes
@@ -613,6 +485,25 @@ void ComputeAndPrintPesqResults(const base::FilePath& reference_file,
} // namespace
+void MAYBE_WebRtcAudioQualityBrowserTest::WriteCapturedAudio(
+ content::WebContents* capturing_tab,
+ const base::FilePath& audio_filename) {
+ base::FilePath audio_filename_webm =
+ audio_filename.AddExtension(FILE_PATH_LITERAL(".webm"));
+
+ std::string base64_encoded_audio =
+ ExecuteJavascript("getRecordedAudioAsBase64()", capturing_tab);
+ std::string recorded_audio;
+ ASSERT_TRUE(base::Base64Decode(base64_encoded_audio, &recorded_audio));
+ base::File audio_file(audio_filename_webm,
+ base::File::FLAG_CREATE | base::File::FLAG_WRITE);
+ size_t written =
+ audio_file.Write(0, recorded_audio.c_str(), recorded_audio.length());
+ ASSERT_EQ(recorded_audio.length(), written);
+
+ RunWebmToWavConverter(audio_filename_webm, audio_filename);
+}
+
// Sets up a two-way WebRTC call and records its output to |recording|, using
// getUserMedia.
//
@@ -627,11 +518,9 @@ void ComputeAndPrintPesqResults(const base::FilePath& reference_file,
void MAYBE_WebRtcAudioQualityBrowserTest::SetupAndRecordAudioCall(
const base::FilePath& reference_file,
const base::FilePath& recording,
- const std::string& constraints,
- const base::TimeDelta recording_time) {
+ const std::string& constraints) {
ASSERT_TRUE(embedded_test_server()->Start());
ASSERT_TRUE(test::HasReferenceFilesInCheckout());
- ASSERT_TRUE(ForceMicrophoneVolumeTo100Percent());
ConfigureFakeDeviceToPlayFile(reference_file);
@@ -647,15 +536,16 @@ void MAYBE_WebRtcAudioQualityBrowserTest::SetupAndRecordAudioCall(
OpenPageAndGetUserMediaInNewTabWithConstraints(test_page, constraints);
SetupPeerconnectionWithLocalStream(right_tab);
- AudioRecorder recorder;
- ASSERT_TRUE(recorder.StartRecording(recording_time, recording));
-
NegotiateCall(left_tab, right_tab);
- ASSERT_TRUE(recorder.WaitForRecordingToEnd());
- DVLOG(0) << "Done recording to " << recording.value() << std::endl;
+ EXPECT_TRUE(test::PollingWaitUntil("doneCapturingAudio()", "done-capturing",
+ right_tab, kPollingIntervalInMs));
HangUp(left_tab);
+
+ WriteCapturedAudio(right_tab, recording);
+
+ DVLOG(0) << "Done recording to " << recording.value() << std::endl;
}
void MAYBE_WebRtcAudioQualityBrowserTest::TestWithFakeDeviceGetUserMedia(
@@ -671,9 +561,8 @@ void MAYBE_WebRtcAudioQualityBrowserTest::TestWithFakeDeviceGetUserMedia(
test::GetReferenceFilesDir().Append(kReferenceFile);
base::FilePath recording = CreateTemporaryWaveFile();
- ASSERT_NO_FATAL_FAILURE(SetupAndRecordAudioCall(
- reference_file, recording, constraints,
- base::TimeDelta::FromSeconds(30)));
+ ASSERT_NO_FATAL_FAILURE(
+ SetupAndRecordAudioCall(reference_file, recording, constraints));
ComputeAndPrintPesqResults(reference_file, recording, perf_modifier);
DeleteFileUnlessTestFailed(recording, false);
@@ -694,8 +583,6 @@ IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioQualityBrowserTest,
ASSERT_TRUE(test::HasReferenceFilesInCheckout());
ASSERT_TRUE(embedded_test_server()->Start());
- ASSERT_TRUE(ForceMicrophoneVolumeTo100Percent());
-
content::WebContents* left_tab =
OpenPageWithoutGetUserMedia(kWebRtcAudioTestHtmlPage);
content::WebContents* right_tab =
@@ -707,19 +594,17 @@ IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcAudioQualityBrowserTest,
base::FilePath recording = CreateTemporaryWaveFile();
- // Note: the sound clip is 21.6 seconds: record for 25 seconds to get some
- // safety margins on each side.
- AudioRecorder recorder;
- ASSERT_TRUE(recorder.StartRecording(base::TimeDelta::FromSeconds(25),
- recording));
-
PlayAudioFileThroughWebAudio(left_tab);
- ASSERT_TRUE(recorder.WaitForRecordingToEnd());
- DVLOG(0) << "Done recording to " << recording.value() << std::endl;
+ EXPECT_TRUE(test::PollingWaitUntil("doneCapturingAudio()", "done-capturing",
+ right_tab, kPollingIntervalInMs));
HangUp(left_tab);
+ WriteCapturedAudio(right_tab, recording);
+
+ DVLOG(0) << "Done recording to " << recording.value() << std::endl;
+
// Compare with the reference file on disk (this is the same file we played
// through WebAudio earlier).
base::FilePath reference_file =
@@ -770,9 +655,8 @@ void MAYBE_WebRtcAudioQualityBrowserTest::TestAutoGainControl(
test::GetReferenceFilesDir().Append(reference_filename);
base::FilePath recording = CreateTemporaryWaveFile();
- ASSERT_NO_FATAL_FAILURE(SetupAndRecordAudioCall(
- reference_file, recording, constraints,
- base::TimeDelta::FromSeconds(30)));
+ ASSERT_NO_FATAL_FAILURE(
+ SetupAndRecordAudioCall(reference_file, recording, constraints));
base::ScopedTempDir split_ref_files;
ASSERT_TRUE(split_ref_files.CreateUniqueTempDir());
« no previous file with comments | « no previous file | chrome/test/data/webrtc/audio_extraction.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698