summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorguidou <guidou@chromium.org>2015-12-18 19:11:03 -0800
committerCommit bot <commit-bot@chromium.org>2015-12-19 03:12:10 +0000
commit19d3df7ad0956e8ac2f366c67957603ca06ff1cf (patch)
treef005186e327bda1d62b2a3e2add62308586dcaaf
parentbcd89d9973489ca59b4433edd5db680dae12b73c (diff)
downloadchromium_src-19d3df7ad0956e8ac2f366c67957603ca06ff1cf.zip
chromium_src-19d3df7ad0956e8ac2f366c67957603ca06ff1cf.tar.gz
chromium_src-19d3df7ad0956e8ac2f366c67957603ca06ff1cf.tar.bz2
Allow diagnostic audio recordings (AEC dumps) through a private API extension protected behind a flag.
TBR=grunell@chromium.org BUG=568169 Review URL: https://codereview.chromium.org/1530863002 Cr-Commit-Position: refs/heads/master@{#366258}
-rw-r--r--chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc89
-rw-r--r--chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.h44
-rw-r--r--chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api_stub.cc12
-rw-r--r--chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc36
-rw-r--r--chrome/browser/media/webrtc_logging_handler_host.cc110
-rw-r--r--chrome/browser/media/webrtc_logging_handler_host.h48
-rw-r--r--chrome/browser/resources/hangout_services/manifest.json2
-rw-r--r--chrome/browser/resources/hangout_services/thunk.js8
-rw-r--r--chrome/common/chrome_switches.cc4
-rw-r--r--chrome/common/chrome_switches.h1
-rw-r--r--chrome/common/extensions/api/webrtc_logging_private.idl36
-rw-r--r--extensions/browser/extension_function_histogram_value.h2
-rw-r--r--tools/metrics/histograms/histograms.xml2
13 files changed, 390 insertions, 4 deletions
diff --git a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc
index cefad21..a1387ea 100644
--- a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc
+++ b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.h"
+#include "base/command_line.h"
#include "base/hash.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
@@ -11,6 +12,7 @@
#include "chrome/browser/extensions/api/tabs/tabs_constants.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_switches.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/site_instance.h"
@@ -36,6 +38,10 @@ namespace StopRtpDump = api::webrtc_logging_private::StopRtpDump;
namespace Store = api::webrtc_logging_private::Store;
namespace Upload = api::webrtc_logging_private::Upload;
namespace UploadStored = api::webrtc_logging_private::UploadStored;
+namespace StartAudioDebugRecordings =
+ api::webrtc_logging_private::StartAudioDebugRecordings;
+namespace StopAudioDebugRecordings =
+ api::webrtc_logging_private::StopAudioDebugRecordings;
namespace {
std::string HashIdWithOrigin(const std::string& security_origin,
@@ -124,6 +130,26 @@ void WebrtcLoggingPrivateFunctionWithUploadCallback::FireCallback(
SendResponse(success);
}
+void WebrtcLoggingPrivateFunctionWithAudioDebugRecordingsCallback::
+ FireErrorCallback(const std::string& error_message) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ SetError(error_message);
+ SendResponse(false);
+}
+
+void WebrtcLoggingPrivateFunctionWithAudioDebugRecordingsCallback::FireCallback(
+ const std::string& prefix_path,
+ bool did_stop,
+ bool did_manual_stop) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ api::webrtc_logging_private::AudioDebugRecordingsInfo result;
+ result.prefix_path = prefix_path;
+ result.did_stop = did_stop;
+ result.did_manual_stop = did_manual_stop;
+ SetResult(result.ToValue().release());
+ SendResponse(true);
+}
+
bool WebrtcLoggingPrivateSetMetaDataFunction::RunAsync() {
scoped_ptr<SetMetaData::Params> params(SetMetaData::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
@@ -348,4 +374,67 @@ bool WebrtcLoggingPrivateStopRtpDumpFunction::RunAsync() {
return true;
}
+bool WebrtcLoggingPrivateStartAudioDebugRecordingsFunction::RunAsync() {
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableAudioDebugRecordingsFromExtension)) {
+ return false;
+ }
+
+ scoped_ptr<StartAudioDebugRecordings::Params> params(
+ StartAudioDebugRecordings::Params::Create(*args_));
+ EXTENSION_FUNCTION_VALIDATE(params.get());
+
+ if (params->seconds < 0) {
+ FireErrorCallback("seconds must be greater than or equal to 0");
+ return true;
+ }
+
+ content::RenderProcessHost* host =
+ RphFromRequest(params->request, params->security_origin);
+ if (!host)
+ return false;
+
+ scoped_refptr<WebRtcLoggingHandlerHost> webrtc_logging_handler_host(
+ base::UserDataAdapter<WebRtcLoggingHandlerHost>::Get(host, host));
+
+ webrtc_logging_handler_host->StartAudioDebugRecordings(
+ host, base::TimeDelta::FromSeconds(params->seconds),
+ base::Bind(
+ &WebrtcLoggingPrivateStartAudioDebugRecordingsFunction::FireCallback,
+ this),
+ base::Bind(&WebrtcLoggingPrivateStartAudioDebugRecordingsFunction::
+ FireErrorCallback,
+ this));
+ return true;
+}
+
+bool WebrtcLoggingPrivateStopAudioDebugRecordingsFunction::RunAsync() {
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableAudioDebugRecordingsFromExtension)) {
+ return false;
+ }
+
+ scoped_ptr<StopAudioDebugRecordings::Params> params(
+ StopAudioDebugRecordings::Params::Create(*args_));
+ EXTENSION_FUNCTION_VALIDATE(params.get());
+
+ content::RenderProcessHost* host =
+ RphFromRequest(params->request, params->security_origin);
+ if (!host)
+ return false;
+
+ scoped_refptr<WebRtcLoggingHandlerHost> webrtc_logging_handler_host(
+ base::UserDataAdapter<WebRtcLoggingHandlerHost>::Get(host, host));
+
+ webrtc_logging_handler_host->StopAudioDebugRecordings(
+ host,
+ base::Bind(
+ &WebrtcLoggingPrivateStopAudioDebugRecordingsFunction::FireCallback,
+ this),
+ base::Bind(&WebrtcLoggingPrivateStopAudioDebugRecordingsFunction::
+ FireErrorCallback,
+ this));
+ return true;
+}
+
} // namespace extensions
diff --git a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.h b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.h
index 202c727..ff5553b 100644
--- a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.h
+++ b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.h
@@ -5,6 +5,8 @@
#ifndef CHROME_BROWSER_EXTENSIONS_API_WEBRTC_LOGGING_PRIVATE_WEBRTC_LOGGING_PRIVATE_API_H_
#define CHROME_BROWSER_EXTENSIONS_API_WEBRTC_LOGGING_PRIVATE_WEBRTC_LOGGING_PRIVATE_API_H_
+#include <string>
+
#include "chrome/browser/extensions/chrome_extension_function.h"
#if defined(ENABLE_WEBRTC)
#include "chrome/browser/media/webrtc_logging_handler_host.h"
@@ -69,6 +71,20 @@ class WebrtcLoggingPrivateFunctionWithUploadCallback
#endif
};
+class WebrtcLoggingPrivateFunctionWithAudioDebugRecordingsCallback
+ : public WebrtcLoggingPrivateFunction {
+ protected:
+ ~WebrtcLoggingPrivateFunctionWithAudioDebugRecordingsCallback() override {}
+
+#if defined(ENABLE_WEBRTC)
+ // Must be called on UI thread.
+ void FireErrorCallback(const std::string& error_message);
+ void FireCallback(const std::string& prefix_path,
+ bool did_stop,
+ bool did_manual_stop);
+#endif
+};
+
class WebrtcLoggingPrivateSetMetaDataFunction
: public WebrtcLoggingPrivateFunctionWithGenericCallback {
public:
@@ -209,6 +225,34 @@ class WebrtcLoggingPrivateStopRtpDumpFunction
bool RunAsync() override;
};
+class WebrtcLoggingPrivateStartAudioDebugRecordingsFunction
+ : public WebrtcLoggingPrivateFunctionWithAudioDebugRecordingsCallback {
+ public:
+ DECLARE_EXTENSION_FUNCTION("webrtcLoggingPrivate.startAudioDebugRecordings",
+ WEBRTCLOGGINGPRIVATE_STARTAUDIODEBUGRECORDINGS)
+ WebrtcLoggingPrivateStartAudioDebugRecordingsFunction() {}
+
+ private:
+ ~WebrtcLoggingPrivateStartAudioDebugRecordingsFunction() override {}
+
+ // ExtensionFunction overrides.
+ bool RunAsync() override;
+};
+
+class WebrtcLoggingPrivateStopAudioDebugRecordingsFunction
+ : public WebrtcLoggingPrivateFunctionWithAudioDebugRecordingsCallback {
+ public:
+ DECLARE_EXTENSION_FUNCTION("webrtcLoggingPrivate.stopAudioDebugRecordings",
+ WEBRTCLOGGINGPRIVATE_STOPAUDIODEBUGRECORDINGS)
+ WebrtcLoggingPrivateStopAudioDebugRecordingsFunction() {}
+
+ private:
+ ~WebrtcLoggingPrivateStopAudioDebugRecordingsFunction() override {}
+
+ // ExtensionFunction overrides.
+ bool RunAsync() override;
+};
+
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_WEBRTC_LOGGING_PRIVATE_WEBRTC_LOGGING_PRIVATE_API_H_
diff --git a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api_stub.cc b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api_stub.cc
index 836e06b..256321e 100644
--- a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api_stub.cc
+++ b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api_stub.cc
@@ -74,4 +74,16 @@ bool WebrtcLoggingPrivateStopRtpDumpFunction::RunAsync() {
return false;
}
+bool WebrtcLoggingPrivateStartAudioDebugRecordingsFunction::RunAsync() {
+ SetError(kErrorNotSupported);
+ SendResponse(false);
+ return false;
+}
+
+bool WebrtcLoggingPrivateStopAudioDebugRecordingsFunction::RunAsync() {
+ SetError(kErrorNotSupported);
+ SendResponse(false);
+ return false;
+}
+
} // namespace extensions
diff --git a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc
index 835e172..b47e8c1 100644
--- a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc
+++ b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc
@@ -12,6 +12,7 @@
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/media/webrtc_log_uploader.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/chrome_switches.h"
#include "components/compression/compression_utils.h"
#include "content/public/browser/notification_service.h"
#include "content/public/test/test_utils.h"
@@ -28,6 +29,8 @@ using extensions::WebrtcLoggingPrivateStopRtpDumpFunction;
using extensions::WebrtcLoggingPrivateStoreFunction;
using extensions::WebrtcLoggingPrivateUploadFunction;
using extensions::WebrtcLoggingPrivateUploadStoredFunction;
+using extensions::WebrtcLoggingPrivateStartAudioDebugRecordingsFunction;
+using extensions::WebrtcLoggingPrivateStopAudioDebugRecordingsFunction;
namespace utils = extension_function_test_utils;
@@ -58,7 +61,6 @@ void InitializeTestMetaData(base::ListValue* parameters) {
class WebrtcLoggingPrivateApiTest : public ExtensionApiTest {
protected:
-
void SetUp() override {
ExtensionApiTest::SetUp();
extension_ = extensions::test_util::CreateEmptyExtension();
@@ -162,6 +164,21 @@ class WebrtcLoggingPrivateApiTest : public ExtensionApiTest {
return RunFunction<WebrtcLoggingPrivateUploadStoredFunction>(params, true);
}
+ bool StartAudioDebugRecordings(int seconds) {
+ base::ListValue params;
+ AppendTabIdAndUrl(&params);
+ params.AppendInteger(seconds);
+ return RunFunction<WebrtcLoggingPrivateStartAudioDebugRecordingsFunction>(
+ params, true);
+ }
+
+ bool StopAudioDebugRecordings() {
+ base::ListValue params;
+ AppendTabIdAndUrl(&params);
+ return RunFunction<WebrtcLoggingPrivateStopAudioDebugRecordingsFunction>(
+ params, true);
+ }
+
private:
scoped_refptr<Extension> extension_;
};
@@ -407,3 +424,20 @@ IN_PROC_BROWSER_TEST_F(WebrtcLoggingPrivateApiTest,
buffer_override.multipart().find(kTestLoggingUrl));
}
+IN_PROC_BROWSER_TEST_F(WebrtcLoggingPrivateApiTest,
+ TestStartStopAudioDebugRecordings) {
+ // TODO(guidou): These tests are missing verification of the actual AEC dump
+ // data. This will be fixed with a separate browser test.
+ // See crbug.com/569957.
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableAudioDebugRecordingsFromExtension);
+ ASSERT_TRUE(StartAudioDebugRecordings(0));
+ ASSERT_TRUE(StopAudioDebugRecordings());
+}
+
+IN_PROC_BROWSER_TEST_F(WebrtcLoggingPrivateApiTest,
+ TestStartTimedAudioDebugRecordings) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableAudioDebugRecordingsFromExtension);
+ ASSERT_TRUE(StartAudioDebugRecordings(1));
+}
diff --git a/chrome/browser/media/webrtc_logging_handler_host.cc b/chrome/browser/media/webrtc_logging_handler_host.cc
index ef7dc19..daa0acc 100644
--- a/chrome/browser/media/webrtc_logging_handler_host.cc
+++ b/chrome/browser/media/webrtc_logging_handler_host.cc
@@ -105,6 +105,15 @@ void FormatMetaDataAsLogMessage(
message->resize(message->size() - 1);
}
+// Returns a path name to be used as prefix for audio debug recordings files.
+base::FilePath GetAudioDebugRecordingsPrefixPath(
+ const base::FilePath& directory,
+ uint64_t audio_debug_recordings_id) {
+ static const char kAudioDebugRecordingsFilePrefix[] = "AudioDebugRecordings.";
+ return directory.AppendASCII(kAudioDebugRecordingsFilePrefix +
+ base::Int64ToString(audio_debug_recordings_id));
+}
+
} // namespace
WebRtcLogBuffer::WebRtcLogBuffer()
@@ -141,12 +150,15 @@ void WebRtcLogBuffer::SetComplete() {
}
WebRtcLoggingHandlerHost::WebRtcLoggingHandlerHost(
- Profile* profile, WebRtcLogUploader* log_uploader)
+ Profile* profile,
+ WebRtcLogUploader* log_uploader)
: BrowserMessageFilter(WebRtcLoggingMsgStart),
profile_(profile),
logging_state_(CLOSED),
upload_log_on_render_close_(false),
- log_uploader_(log_uploader) {
+ log_uploader_(log_uploader),
+ is_audio_debug_recordings_in_progress_(false),
+ current_audio_debug_recordings_id_(0) {
DCHECK(profile_);
DCHECK(log_uploader_);
}
@@ -429,6 +441,35 @@ void WebRtcLoggingHandlerHost::DumpRtpPacketOnIOThread(
}
}
+void WebRtcLoggingHandlerHost::StartAudioDebugRecordings(
+ content::RenderProcessHost* host,
+ base::TimeDelta delay,
+ const AudioDebugRecordingsCallback& callback,
+ const AudioDebugRecordingsErrorCallback& error_callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ BrowserThread::PostTaskAndReplyWithResult(
+ BrowserThread::FILE, FROM_HERE,
+ base::Bind(&WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists,
+ this),
+ base::Bind(&WebRtcLoggingHandlerHost::DoStartAudioDebugRecordings, this,
+ host, delay, callback, error_callback));
+}
+
+void WebRtcLoggingHandlerHost::StopAudioDebugRecordings(
+ content::RenderProcessHost* host,
+ const AudioDebugRecordingsCallback& callback,
+ const AudioDebugRecordingsErrorCallback& error_callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ BrowserThread::PostTaskAndReplyWithResult(
+ BrowserThread::FILE, FROM_HERE,
+ base::Bind(&WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists,
+ this),
+ base::Bind(&WebRtcLoggingHandlerHost::DoStopAudioDebugRecordings, this,
+ host, true /* manual stop */,
+ current_audio_debug_recordings_id_, callback, error_callback));
+}
+
void WebRtcLoggingHandlerHost::OnChannelClosing() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (logging_state_ == STARTED || logging_state_ == STOPPED) {
@@ -765,3 +806,68 @@ void WebRtcLoggingHandlerHost::FireGenericDoneCallback(
FROM_HERE,
base::Bind(callback, success, error_message_with_state));
}
+
+void WebRtcLoggingHandlerHost::DoStartAudioDebugRecordings(
+ content::RenderProcessHost* host,
+ base::TimeDelta delay,
+ const AudioDebugRecordingsCallback& callback,
+ const AudioDebugRecordingsErrorCallback& error_callback,
+ const base::FilePath& log_directory) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ if (is_audio_debug_recordings_in_progress_) {
+ error_callback.Run("Audio debug recordings already in progress");
+ return;
+ }
+
+ is_audio_debug_recordings_in_progress_ = true;
+ base::FilePath prefix_path = GetAudioDebugRecordingsPrefixPath(
+ log_directory, ++current_audio_debug_recordings_id_);
+ host->EnableAudioDebugRecordings(prefix_path);
+
+ if (delay.is_zero()) {
+ callback.Run(prefix_path.AsUTF8Unsafe(), false /* not stopped */,
+ false /* not manually stopped */);
+ return;
+ }
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&WebRtcLoggingHandlerHost::DoStopAudioDebugRecordings, this,
+ host, false /* no manual stop */,
+ current_audio_debug_recordings_id_, callback, error_callback,
+ prefix_path));
+}
+
+void WebRtcLoggingHandlerHost::DoStopAudioDebugRecordings(
+ content::RenderProcessHost* host,
+ bool is_manual_stop,
+ uint64_t audio_debug_recordings_id,
+ const AudioDebugRecordingsCallback& callback,
+ const AudioDebugRecordingsErrorCallback& error_callback,
+ const base::FilePath& log_directory) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK_LE(audio_debug_recordings_id, current_audio_debug_recordings_id_);
+
+ base::FilePath prefix_path = GetAudioDebugRecordingsPrefixPath(
+ log_directory, audio_debug_recordings_id);
+ // Prevent an old posted StopAudioDebugRecordings() call to stop a newer dump.
+ // This could happen in a sequence like:
+ // Start(10); //Start dump 1. Post Stop() to run after 10 seconds.
+ // Stop(); // Manually stop dump 1 before 10 seconds;
+ // Start(20); // Start dump 2. Posted Stop() for 1 should not stop dump 2.
+ if (audio_debug_recordings_id < current_audio_debug_recordings_id_) {
+ callback.Run(prefix_path.AsUTF8Unsafe(), false /* not stopped */,
+ is_manual_stop);
+ return;
+ }
+
+ if (!is_audio_debug_recordings_in_progress_) {
+ error_callback.Run("No audio debug recording in progress");
+ return;
+ }
+
+ host->DisableAudioDebugRecordings();
+ is_audio_debug_recordings_in_progress_ = false;
+ callback.Run(prefix_path.AsUTF8Unsafe(), true /* stopped */, is_manual_stop);
+}
diff --git a/chrome/browser/media/webrtc_logging_handler_host.h b/chrome/browser/media/webrtc_logging_handler_host.h
index c2b3e32..d62d6cc 100644
--- a/chrome/browser/media/webrtc_logging_handler_host.h
+++ b/chrome/browser/media/webrtc_logging_handler_host.h
@@ -77,6 +77,10 @@ class WebRtcLoggingHandlerHost : public content::BrowserMessageFilter {
typedef base::Callback<void(bool, const std::string&)> GenericDoneCallback;
typedef base::Callback<void(bool, const std::string&, const std::string&)>
UploadDoneCallback;
+ typedef base::Callback<void(const std::string&)>
+ AudioDebugRecordingsErrorCallback;
+ typedef base::Callback<void(const std::string&, bool, bool)>
+ AudioDebugRecordingsCallback;
WebRtcLoggingHandlerHost(Profile* profile, WebRtcLogUploader* log_uploader);
@@ -146,6 +150,27 @@ class WebRtcLoggingHandlerHost : public content::BrowserMessageFilter {
size_t packet_length,
bool incoming);
+ // Starts an audio debug recording. The recording lasts the given |delay|,
+ // unless |delay| is zero, in which case recording will continue until
+ // StopAudioDebugRecordings() is explicitly invoked.
+ // |callback| is invoked once recording stops. If |delay| is zero
+ // |callback| is invoked once recording starts.
+ // If a recording was already in progress, |error_callback| is invoked instead
+ // of |callback|.
+ void StartAudioDebugRecordings(
+ content::RenderProcessHost* host,
+ base::TimeDelta delay,
+ const AudioDebugRecordingsCallback& callback,
+ const AudioDebugRecordingsErrorCallback& error_callback);
+
+ // Stops an audio debug recording. |callback| is invoked once recording
+ // stops. If no recording was in progress, |error_callback| is invoked instead
+ // of |callback|.
+ void StopAudioDebugRecordings(
+ content::RenderProcessHost* host,
+ const AudioDebugRecordingsCallback& callback,
+ const AudioDebugRecordingsErrorCallback& error_callback);
+
private:
// States used for protecting from function calls made at non-allowed points
// in time. For example, StartLogging() is only allowed in CLOSED state.
@@ -232,6 +257,23 @@ class WebRtcLoggingHandlerHost : public content::BrowserMessageFilter {
bool success,
const std::string& error_message);
+ // Helper for starting audio debug recordings.
+ void DoStartAudioDebugRecordings(
+ content::RenderProcessHost* host,
+ base::TimeDelta delay,
+ const AudioDebugRecordingsCallback& callback,
+ const AudioDebugRecordingsErrorCallback& error_callback,
+ const base::FilePath& log_directory);
+
+ // Helper for stopping audio debug recordings.
+ void DoStopAudioDebugRecordings(
+ content::RenderProcessHost* host,
+ bool is_manual_stop,
+ uint64_t audio_debug_recordings_id,
+ const AudioDebugRecordingsCallback& callback,
+ const AudioDebugRecordingsErrorCallback& error_callback,
+ const base::FilePath& log_directory);
+
scoped_ptr<WebRtcLogBuffer> log_buffer_;
// The profile associated with our renderer process.
@@ -273,6 +315,12 @@ class WebRtcLoggingHandlerHost : public content::BrowserMessageFilter {
// Ownership lies with the browser process.
WebRtcLogUploader* const log_uploader_;
+ // Must be accessed on the UI thread.
+ bool is_audio_debug_recordings_in_progress_;
+
+ // This counter allows saving each debug recording in separate files.
+ uint64_t current_audio_debug_recordings_id_;
+
DISALLOW_COPY_AND_ASSIGN(WebRtcLoggingHandlerHost);
};
diff --git a/chrome/browser/resources/hangout_services/manifest.json b/chrome/browser/resources/hangout_services/manifest.json
index 211426e..92255eb 100644
--- a/chrome/browser/resources/hangout_services/manifest.json
+++ b/chrome/browser/resources/hangout_services/manifest.json
@@ -5,7 +5,7 @@
"name": "Google Hangouts",
// Note: Always update the version number when this file is updated. Chrome
// triggers extension preferences update on the version increase.
- "version": "1.1.2",
+ "version": "1.2.0",
"manifest_version": 2,
"externally_connectable": {
"matches": [
diff --git a/chrome/browser/resources/hangout_services/thunk.js b/chrome/browser/resources/hangout_services/thunk.js
index d03a831..dd24d6f 100644
--- a/chrome/browser/resources/hangout_services/thunk.js
+++ b/chrome/browser/resources/hangout_services/thunk.js
@@ -167,6 +167,14 @@ chrome.runtime.onMessageExternal.addListener(
chrome.webrtcLoggingPrivate.stopRtpDump(
requestInfo, origin, incoming, outgoing, doSendResponse);
return true;
+ } else if (method == 'logging.startAudioDebugRecordings') {
+ var seconds = message['seconds'] || 0;
+ chrome.webrtcLoggingPrivate.startAudioDebugRecordings(
+ seconds, doSendResponse);
+ return true;
+ } else if (method == 'logging.stopAudioDebugRecordings') {
+ chrome.webrtcLoggingPrivate.stopAudioDebugRecordings(doSendResponse);
+ return true;
}
throw new Error('Unknown method: ' + method);
} catch (e) {
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index c9c92498..7b7bbbc 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -375,6 +375,10 @@ const char kEnableAddToShelf[] = "enable-add-to-shelf";
// Enable OS integration for Chrome app file associations.
const char kEnableAppsFileAssociations[] = "enable-apps-file-associations";
+// If the WebRTC logging private API is active, enables audio debug recordings.
+const char kEnableAudioDebugRecordingsFromExtension[] =
+ "enable-audio-debug-recordings-from-extension";
+
// Enables the benchmarking extensions.
const char kEnableBenchmarking[] = "enable-benchmarking";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 22914f1..81a368c 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -109,6 +109,7 @@ extern const char kDumpBrowserHistograms[];
extern const char kEasyUnlockAppPath[];
extern const char kEnableAddToShelf[];
extern const char kEnableAppsFileAssociations[];
+extern const char kEnableAudioDebugRecordingsFromExtension[];
extern const char kEnableBenchmarking[];
extern const char kEnableBookmarkUndo[];
extern const char kEnableChildAccountDetection[];
diff --git a/chrome/common/extensions/api/webrtc_logging_private.idl b/chrome/common/extensions/api/webrtc_logging_private.idl
index 5c72c95..0f900f9 100644
--- a/chrome/common/extensions/api/webrtc_logging_private.idl
+++ b/chrome/common/extensions/api/webrtc_logging_private.idl
@@ -28,7 +28,23 @@ namespace webrtcLoggingPrivate {
long? guestProcessId;
};
+ // This contains information about the result of audio debug recordings.
+ dictionary AudioDebugRecordingsInfo {
+ // Absolute path prefix for the files with the audio debug recordings.
+ DOMString prefixPath;
+
+ // Indicates if recording was stopped.
+ boolean didStop;
+
+ // Indicates if recording was stopped manually through a
+ // stopAudioDebugRecordings() call.
+ boolean didManualStop;
+ };
+
+
callback GenericDoneCallback = void ();
+ callback AudioDebugRecordingsCallback =
+ void (AudioDebugRecordingsInfo info);
callback UploadDoneCallback = void (UploadResult result);
interface Functions {
@@ -111,5 +127,25 @@ namespace webrtcLoggingPrivate {
boolean incoming,
boolean outgoing,
GenericDoneCallback callback);
+
+ // Starts audio debug recordings.
+ // |seconds| indicates how many seconds of audio to record. |callback|
+ // is invoked once recording stops.
+ // If |seconds| is zero, recording will continue until
+ // stopAudioDebugRecordings() is explicitly called. In this case,
+ // |callback| is invoked once recording starts and will report
+ // that recording has not stopped.
+ // If |seconds| is negative, startAudioDebugRecordings() fails.
+ static void startAudioDebugRecordings(RequestInfo request,
+ DOMString securityOrigin,
+ long seconds,
+ AudioDebugRecordingsCallback callback);
+
+ // Stops audio debug recordings. |callback| is invoked once recording
+ // stops. If there is no recording in progress, stopAudioDebugRecordings()
+ // fails.
+ static void stopAudioDebugRecordings(RequestInfo request,
+ DOMString securityOrigin,
+ AudioDebugRecordingsCallback callback);
};
};
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index 7820b7f..588b05e 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -1158,6 +1158,8 @@ enum HistogramValue {
BLUETOOTHPRIVATE_FORGETDEVICE,
DISPLAYSOURCE_GETAVAILABLESINKS,
DISPLAYSOURCE_REQUESTAUTHENTICATION,
+ WEBRTCLOGGINGPRIVATE_STARTAUDIODEBUGRECORDINGS,
+ WEBRTCLOGGINGPRIVATE_STOPAUDIODEBUGRECORDINGS,
// Last entry: Add new entries above, then run:
// python tools/metrics/histograms/update_extension_histograms.py
ENUM_BOUNDARY
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 20fafda..3fe2253 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -62793,6 +62793,8 @@ http://cs/file:chrome/histograms.xml - but prefer this file for new entries.
<int value="1097" label="BLUETOOTHPRIVATE_FORGETDEVICE"/>
<int value="1098" label="DISPLAYSOURCE_GETAVAILABLESINKS"/>
<int value="1099" label="DISPLAYSOURCE_REQUESTAUTHENTICATION"/>
+ <int value="1100" label="WEBRTCLOGGINGPRIVATE_STARTAUDIODEBUGRECORDINGS"/>
+ <int value="1101" label="WEBRTCLOGGINGPRIVATE_STOPAUDIODEBUGRECORDINGS"/>
</enum>
<enum name="ExtensionInstallCause" type="int">