Commit c6d46d2f authored by Marina Ciocea's avatar Marina Ciocea Committed by Commit Bot

Introduce debug recording Mojo implementation.

* add mojo interfaces for enabling debug recording and creating debug recording files.
* add debug recording session factory to toggle between media/audio/ and services/audio/ debug recording implementations.

Design doc: http://doc/123YGEhyyDqbO1440rwdg0T_4UPxNyZmJboczjFIZpMI#heading=h.xpzwbhip9is6

This CL depends on [1]. Switching to mojo implementation will be done in [2].

[1] https://crrev.com/c/875927
[2] https://crrev.com/c/921281

Bug: 788657
Cq-Include-Trybots: master.tryserver.chromium.android:android_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel
Change-Id: Idbbfdb89c6ad4ff373ac25db83b5ed4ef6167b86
Reviewed-on: https://chromium-review.googlesource.com/810809Reviewed-by: default avatarTommi <tommi@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Reviewed-by: default avatarKen Rockot <rockot@chromium.org>
Reviewed-by: default avatarGuido Urdaneta <guidou@chromium.org>
Reviewed-by: default avatarOlga Sharonova <olka@chromium.org>
Reviewed-by: default avatarMax Morin <maxmorin@chromium.org>
Commit-Queue: Marina Ciocea <marinaciocea@chromium.org>
Cr-Commit-Position: refs/heads/master@{#539134}
parent 5a9ac91d
...@@ -4152,6 +4152,7 @@ jumbo_split_static_library("browser") { ...@@ -4152,6 +4152,7 @@ jumbo_split_static_library("browser") {
deps += [ deps += [
"//components/webrtc_logging/browser", "//components/webrtc_logging/browser",
"//components/webrtc_logging/common", "//components/webrtc_logging/common",
"//services/audio/public/cpp",
"//third_party/webrtc_overrides", "//third_party/webrtc_overrides",
"//third_party/webrtc_overrides:init_webrtc", "//third_party/webrtc_overrides:init_webrtc",
] ]
......
include_rules = [ include_rules = [
# TODO(mash): Remove. http://crbug.com/723880 # TODO(mash): Remove. http://crbug.com/723880
"+ash/shell.h", "+ash/shell.h",
"+services/audio/public/cpp",
"+third_party/libyuv", "+third_party/libyuv",
"+third_party/webrtc", "+third_party/webrtc",
] ]
......
...@@ -17,7 +17,10 @@ ...@@ -17,7 +17,10 @@
#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h" #include "content/public/browser/render_process_host.h"
#include "content/public/common/service_manager_connection.h"
#include "media/audio/audio_debug_recording_session.h" #include "media/audio/audio_debug_recording_session.h"
#include "services/audio/public/cpp/debug_recording_session_factory.h"
#include "services/service_manager/public/cpp/connector.h"
using content::BrowserThread; using content::BrowserThread;
...@@ -106,8 +109,10 @@ void AudioDebugRecordingsHandler::DoStartAudioDebugRecordings( ...@@ -106,8 +109,10 @@ void AudioDebugRecordingsHandler::DoStartAudioDebugRecordings(
log_directory, ++current_audio_debug_recordings_id_); log_directory, ++current_audio_debug_recordings_id_);
host->EnableAudioDebugRecordings(prefix_path); host->EnableAudioDebugRecordings(prefix_path);
audio_debug_recording_session_ = audio_debug_recording_session_ = audio::CreateAudioDebugRecordingSession(
media::AudioDebugRecordingSession::Create(prefix_path); prefix_path, content::ServiceManagerConnection::GetForProcess()
->GetConnector()
->Clone());
if (delay.is_zero()) { if (delay.is_zero()) {
const bool is_stopped = false, is_manual_stop = false; const bool is_stopped = false, is_manual_stop = false;
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "media/audio/audio_debug_recording_session.h" #include "media/audio/audio_debug_recording_session.h"
#include "media/audio/audio_manager.h" #include "media/audio/audio_manager.h"
#include "media/media_features.h" #include "media/media_features.h"
#include "services/audio/public/cpp/debug_recording_session_factory.h"
#include "services/device/public/mojom/constants.mojom.h" #include "services/device/public/mojom/constants.mojom.h"
#include "services/device/public/mojom/wake_lock_provider.mojom.h" #include "services/device/public/mojom/wake_lock_provider.mojom.h"
#include "services/service_manager/public/cpp/connector.h" #include "services/service_manager/public/cpp/connector.h"
...@@ -518,8 +519,11 @@ void WebRTCInternals::OnRendererExit(int render_process_id) { ...@@ -518,8 +519,11 @@ void WebRTCInternals::OnRendererExit(int render_process_id) {
void WebRTCInternals::EnableAudioDebugRecordingsOnAllRenderProcessHosts() { void WebRTCInternals::EnableAudioDebugRecordingsOnAllRenderProcessHosts() {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!audio_debug_recording_session_); DCHECK(!audio_debug_recording_session_);
audio_debug_recording_session_ = media::AudioDebugRecordingSession::Create( audio_debug_recording_session_ = audio::CreateAudioDebugRecordingSession(
audio_debug_recordings_file_path_); audio_debug_recordings_file_path_,
content::ServiceManagerConnection::GetForProcess()
->GetConnector()
->Clone());
for (RenderProcessHost::iterator i( for (RenderProcessHost::iterator i(
content::RenderProcessHost::AllHostsIterator()); content::RenderProcessHost::AllHostsIterator());
......
...@@ -71,7 +71,7 @@ ...@@ -71,7 +71,7 @@
}, },
"requires": { "requires": {
"*": [ "app" ], "*": [ "app" ],
"audio": [ "info" ], "audio": [ "info", "debug_recording"],
"cdm": [ "media:cdm" ], "cdm": [ "media:cdm" ],
"content_gpu": [ "browser" ], "content_gpu": [ "browser" ],
"content_plugin": [ "browser" ], "content_plugin": [ "browser" ],
......
...@@ -73,7 +73,6 @@ source_set("audio") { ...@@ -73,7 +73,6 @@ source_set("audio") {
"audio_debug_recording_helper.h", "audio_debug_recording_helper.h",
"audio_debug_recording_manager.cc", "audio_debug_recording_manager.cc",
"audio_debug_recording_manager.h", "audio_debug_recording_manager.h",
"audio_debug_recording_session.cc",
"audio_debug_recording_session.h", "audio_debug_recording_session.h",
"audio_debug_recording_session_impl.cc", "audio_debug_recording_session_impl.cc",
"audio_debug_recording_session_impl.h", "audio_debug_recording_session_impl.h",
...@@ -338,6 +337,8 @@ static_library("test_support") { ...@@ -338,6 +337,8 @@ static_library("test_support") {
visibility = [ "//media:test_support" ] visibility = [ "//media:test_support" ]
testonly = true testonly = true
sources = [ sources = [
"audio_debug_recording_test.cc",
"audio_debug_recording_test.h",
"audio_device_info_accessor_for_tests.cc", "audio_device_info_accessor_for_tests.cc",
"audio_device_info_accessor_for_tests.h", "audio_device_info_accessor_for_tests.h",
"audio_system_test_util.cc", "audio_system_test_util.cc",
...@@ -361,6 +362,7 @@ static_library("test_support") { ...@@ -361,6 +362,7 @@ static_library("test_support") {
] ]
deps = [ deps = [
"//base", "//base",
"//base/test:test_support",
# Do not add any other //media deps except this; it will automatically pull # Do not add any other //media deps except this; it will automatically pull
# a dep on //media which is required to ensure test_support targets all use # a dep on //media which is required to ensure test_support targets all use
......
...@@ -304,8 +304,4 @@ bool AudioDebugFileWriter::WillWrite() { ...@@ -304,8 +304,4 @@ bool AudioDebugFileWriter::WillWrite() {
return !!file_writer_; return !!file_writer_;
} }
const base::FilePath::CharType* AudioDebugFileWriter::GetFileExtension() {
return FILE_PATH_LITERAL("wav");
}
} // namespace media } // namespace media
...@@ -52,11 +52,6 @@ class MEDIA_EXPORT AudioDebugFileWriter { ...@@ -52,11 +52,6 @@ class MEDIA_EXPORT AudioDebugFileWriter {
// called from any sequence. // called from any sequence.
virtual bool WillWrite(); virtual bool WillWrite();
// Gets the extension for the file type the as a string, for example "wav".
// Can be called before calling Start() to add the appropriate extension to
// the filename.
virtual const base::FilePath::CharType* GetFileExtension();
protected: protected:
const AudioParameters params_; const AudioParameters params_;
......
...@@ -242,12 +242,6 @@ TEST_P(AudioDebugFileWriterTest, WaveRecordingTest) { ...@@ -242,12 +242,6 @@ TEST_P(AudioDebugFileWriterTest, WaveRecordingTest) {
RecordAndVerifyOnce(); RecordAndVerifyOnce();
} }
TEST_P(AudioDebugFileWriterTest, GetFileExtension) {
debug_writer_.reset(new AudioDebugFileWriter(params_));
EXPECT_EQ(FILE_PATH_LITERAL("wav"),
base::FilePath::StringType(debug_writer_->GetFileExtension()));
}
TEST_P(AudioDebugFileWriterSingleThreadTest, TEST_P(AudioDebugFileWriterSingleThreadTest,
DeletedBeforeRecordingFinishedOnFileThread) { DeletedBeforeRecordingFinishedOnFileThread) {
debug_writer_.reset(new AudioDebugFileWriter(params_)); debug_writer_.reset(new AudioDebugFileWriter(params_));
......
...@@ -32,13 +32,13 @@ AudioDebugRecordingHelper::~AudioDebugRecordingHelper() { ...@@ -32,13 +32,13 @@ AudioDebugRecordingHelper::~AudioDebugRecordingHelper() {
void AudioDebugRecordingHelper::EnableDebugRecording( void AudioDebugRecordingHelper::EnableDebugRecording(
const base::FilePath& file_name_suffix, const base::FilePath& file_name_suffix,
CreateFileCallback create_file_callback) { CreateWavFileCallback create_file_callback) {
DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK(!debug_writer_); DCHECK(!debug_writer_);
debug_writer_ = CreateAudioDebugFileWriter(params_); debug_writer_ = CreateAudioDebugFileWriter(params_);
std::move(create_file_callback) std::move(create_file_callback)
.Run(file_name_suffix.AddExtension(debug_writer_->GetFileExtension()), .Run(file_name_suffix,
base::BindOnce(&AudioDebugRecordingHelper::StartDebugRecordingToFile, base::BindOnce(&AudioDebugRecordingHelper::StartDebugRecordingToFile,
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()));
} }
......
...@@ -50,7 +50,7 @@ class AudioDebugRecorder { ...@@ -50,7 +50,7 @@ class AudioDebugRecorder {
// soundcard thread -> file thread. // soundcard thread -> file thread.
class MEDIA_EXPORT AudioDebugRecordingHelper : public AudioDebugRecorder { class MEDIA_EXPORT AudioDebugRecordingHelper : public AudioDebugRecorder {
public: public:
using CreateFileCallback = base::OnceCallback<void( using CreateWavFileCallback = base::OnceCallback<void(
const base::FilePath&, const base::FilePath&,
base::OnceCallback<void(base::File)> reply_callback)>; base::OnceCallback<void(base::File)> reply_callback)>;
...@@ -63,7 +63,7 @@ class MEDIA_EXPORT AudioDebugRecordingHelper : public AudioDebugRecorder { ...@@ -63,7 +63,7 @@ class MEDIA_EXPORT AudioDebugRecordingHelper : public AudioDebugRecorder {
// Enable debug recording. Creates |debug_writer_| and runs // Enable debug recording. Creates |debug_writer_| and runs
// |create_file_callback| to create debug recording file. // |create_file_callback| to create debug recording file.
virtual void EnableDebugRecording(const base::FilePath& file_name_suffix, virtual void EnableDebugRecording(const base::FilePath& file_name_suffix,
CreateFileCallback create_file_callback); CreateWavFileCallback create_file_callback);
// Disable debug recording. Destroys |debug_writer_|. // Disable debug recording. Destroys |debug_writer_|.
virtual void DisableDebugRecording(); virtual void DisableDebugRecording();
......
...@@ -43,8 +43,7 @@ const base::FilePath::CharType kBaseFileName[] = ...@@ -43,8 +43,7 @@ const base::FilePath::CharType kBaseFileName[] =
const base::FilePath::CharType kFileNameSuffix[] = const base::FilePath::CharType kFileNameSuffix[] =
FILE_PATH_LITERAL("output.1"); FILE_PATH_LITERAL("output.1");
// The file extension the mock should return in GetFileExtension(). const base::FilePath::CharType kWavExtension[] = FILE_PATH_LITERAL("wav");
const base::FilePath::CharType kFileExtension[] = FILE_PATH_LITERAL("wav");
} // namespace } // namespace
...@@ -76,7 +75,6 @@ class MockAudioDebugFileWriter : public AudioDebugFileWriter { ...@@ -76,7 +75,6 @@ class MockAudioDebugFileWriter : public AudioDebugFileWriter {
} }
MOCK_METHOD0(WillWrite, bool()); MOCK_METHOD0(WillWrite, bool());
MOCK_METHOD0(GetFileExtension, const base::FilePath::CharType*());
// Set reference data to compare against. Must be called before Write() is // Set reference data to compare against. Must be called before Write() is
// called. // called.
...@@ -107,11 +105,10 @@ class AudioDebugRecordingHelperUnderTest : public AudioDebugRecordingHelper { ...@@ -107,11 +105,10 @@ class AudioDebugRecordingHelperUnderTest : public AudioDebugRecordingHelper {
private: private:
// Creates the mock writer. After the mock writer is returned, we always // Creates the mock writer. After the mock writer is returned, we always
// expect GetFileExtension() and Start() to be called on it by the helper. // expect Start() to be called on it by the helper.
std::unique_ptr<AudioDebugFileWriter> CreateAudioDebugFileWriter( std::unique_ptr<AudioDebugFileWriter> CreateAudioDebugFileWriter(
const AudioParameters& params) override { const AudioParameters& params) override {
MockAudioDebugFileWriter* writer = new MockAudioDebugFileWriter(params); MockAudioDebugFileWriter* writer = new MockAudioDebugFileWriter(params);
EXPECT_CALL(*writer, GetFileExtension()).WillOnce(Return(kFileExtension));
EXPECT_CALL(*writer, DoStart(true)); EXPECT_CALL(*writer, DoStart(true));
return base::WrapUnique<AudioDebugFileWriter>(writer); return base::WrapUnique<AudioDebugFileWriter>(writer);
} }
...@@ -139,20 +136,21 @@ class AudioDebugRecordingHelperTest : public ::testing::Test { ...@@ -139,20 +136,21 @@ class AudioDebugRecordingHelperTest : public ::testing::Test {
MOCK_METHOD0(OnAudioDebugRecordingHelperDestruction, void()); MOCK_METHOD0(OnAudioDebugRecordingHelperDestruction, void());
// Bound and passed to AudioDebugRecordingHelper::EnableDebugRecording as // Bound and passed to AudioDebugRecordingHelper::EnableDebugRecording as
// AudioDebugRecordingHelper::CreateFileCallback. // AudioDebugRecordingHelper::CreateWavFileCallback.
void CreateFile(const base::FilePath& file_name_suffix, void CreateWavFile(const base::FilePath& file_name_suffix,
base::OnceCallback<void(base::File)> reply_callback) { base::OnceCallback<void(base::File)> reply_callback) {
// Check that AudioDebugRecordingHelper::EnableDebugRecording adds file // Check that AudioDebugRecordingHelper::EnableDebugRecording adds file
// extension to file name suffix. // extension to file name suffix.
EXPECT_EQ(file_name_suffix_.AddExtension(kFileExtension), file_name_suffix); EXPECT_EQ(file_name_suffix_, file_name_suffix);
base::ScopedTempDir temp_dir; base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
base::FilePath base_file_path( base::FilePath base_file_path(
temp_dir.GetPath().Append(base::FilePath(kBaseFileName))); temp_dir.GetPath().Append(base::FilePath(kBaseFileName)));
base::FilePath file_path = base::FilePath file_path =
base_file_path.AddExtension(file_name_suffix.value()); base_file_path.AddExtension(file_name_suffix.value())
base::File debug_file(base::File( .AddExtension(kWavExtension);
file_path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE)); base::File debug_file(
file_path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
// Run |reply_callback| with a valid file for expected // Run |reply_callback| with a valid file for expected
// MockAudioDebugFileWriter::Start mocked call to happen. // MockAudioDebugFileWriter::Start mocked call to happen.
std::move(reply_callback).Run(std::move(debug_file)); std::move(reply_callback).Run(std::move(debug_file));
...@@ -199,7 +197,7 @@ TEST_F(AudioDebugRecordingHelperTest, EnableDisable) { ...@@ -199,7 +197,7 @@ TEST_F(AudioDebugRecordingHelperTest, EnableDisable) {
recording_helper->EnableDebugRecording( recording_helper->EnableDebugRecording(
file_name_suffix_, file_name_suffix_,
base::BindOnce(&AudioDebugRecordingHelperTest::CreateFile, base::BindOnce(&AudioDebugRecordingHelperTest::CreateWavFile,
base::Unretained(this))); base::Unretained(this)));
EXPECT_CALL(*static_cast<MockAudioDebugFileWriter*>( EXPECT_CALL(*static_cast<MockAudioDebugFileWriter*>(
recording_helper->debug_writer_.get()), recording_helper->debug_writer_.get()),
...@@ -208,7 +206,7 @@ TEST_F(AudioDebugRecordingHelperTest, EnableDisable) { ...@@ -208,7 +206,7 @@ TEST_F(AudioDebugRecordingHelperTest, EnableDisable) {
recording_helper->EnableDebugRecording( recording_helper->EnableDebugRecording(
file_name_suffix_, file_name_suffix_,
base::BindOnce(&AudioDebugRecordingHelperTest::CreateFile, base::BindOnce(&AudioDebugRecordingHelperTest::CreateWavFile,
base::Unretained(this))); base::Unretained(this)));
EXPECT_CALL(*static_cast<MockAudioDebugFileWriter*>( EXPECT_CALL(*static_cast<MockAudioDebugFileWriter*>(
recording_helper->debug_writer_.get()), recording_helper->debug_writer_.get()),
...@@ -242,7 +240,7 @@ TEST_F(AudioDebugRecordingHelperTest, OnData) { ...@@ -242,7 +240,7 @@ TEST_F(AudioDebugRecordingHelperTest, OnData) {
recording_helper->EnableDebugRecording( recording_helper->EnableDebugRecording(
file_name_suffix_, file_name_suffix_,
base::BindOnce(&AudioDebugRecordingHelperTest::CreateFile, base::BindOnce(&AudioDebugRecordingHelperTest::CreateWavFile,
base::Unretained(this))); base::Unretained(this)));
MockAudioDebugFileWriter* mock_audio_file_writer = MockAudioDebugFileWriter* mock_audio_file_writer =
static_cast<MockAudioDebugFileWriter*>( static_cast<MockAudioDebugFileWriter*>(
...@@ -264,7 +262,7 @@ TEST_F(AudioDebugRecordingHelperTest, OnData) { ...@@ -264,7 +262,7 @@ TEST_F(AudioDebugRecordingHelperTest, OnData) {
// disabling. // disabling.
recording_helper->EnableDebugRecording( recording_helper->EnableDebugRecording(
file_name_suffix_, file_name_suffix_,
base::BindOnce(&AudioDebugRecordingHelperTest::CreateFile, base::BindOnce(&AudioDebugRecordingHelperTest::CreateWavFile,
base::Unretained(this))); base::Unretained(this)));
mock_audio_file_writer = static_cast<MockAudioDebugFileWriter*>( mock_audio_file_writer = static_cast<MockAudioDebugFileWriter*>(
recording_helper->debug_writer_.get()); recording_helper->debug_writer_.get());
......
...@@ -42,7 +42,7 @@ AudioDebugRecordingManager::AudioDebugRecordingManager( ...@@ -42,7 +42,7 @@ AudioDebugRecordingManager::AudioDebugRecordingManager(
AudioDebugRecordingManager::~AudioDebugRecordingManager() = default; AudioDebugRecordingManager::~AudioDebugRecordingManager() = default;
void AudioDebugRecordingManager::EnableDebugRecording( void AudioDebugRecordingManager::EnableDebugRecording(
CreateFileCallback create_file_callback) { CreateWavFileCallback create_file_callback) {
DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK(!create_file_callback.is_null()); DCHECK(!create_file_callback.is_null());
create_file_callback_ = std::move(create_file_callback); create_file_callback_ = std::move(create_file_callback);
......
...@@ -57,7 +57,7 @@ namespace media { ...@@ -57,7 +57,7 @@ namespace media {
class MEDIA_EXPORT AudioDebugRecordingManager { class MEDIA_EXPORT AudioDebugRecordingManager {
public: public:
using CreateFileCallback = base::RepeatingCallback<void( using CreateWavFileCallback = base::RepeatingCallback<void(
const base::FilePath&, const base::FilePath&,
base::OnceCallback<void(base::File)> reply_callback)>; base::OnceCallback<void(base::File)> reply_callback)>;
...@@ -66,7 +66,7 @@ class MEDIA_EXPORT AudioDebugRecordingManager { ...@@ -66,7 +66,7 @@ class MEDIA_EXPORT AudioDebugRecordingManager {
virtual ~AudioDebugRecordingManager(); virtual ~AudioDebugRecordingManager();
// Enables and disables debug recording. // Enables and disables debug recording.
virtual void EnableDebugRecording(CreateFileCallback create_file_callback); virtual void EnableDebugRecording(CreateWavFileCallback create_file_callback);
virtual void DisableDebugRecording(); virtual void DisableDebugRecording();
// Registers a source and returns a wrapped recorder. |stream_type| is added // Registers a source and returns a wrapped recorder. |stream_type| is added
...@@ -110,7 +110,7 @@ class MEDIA_EXPORT AudioDebugRecordingManager { ...@@ -110,7 +110,7 @@ class MEDIA_EXPORT AudioDebugRecordingManager {
// Callback for creating debug recording files. When this is not null, debug // Callback for creating debug recording files. When this is not null, debug
// recording is enabled. // recording is enabled.
CreateFileCallback create_file_callback_; CreateWavFileCallback create_file_callback_;
base::WeakPtrFactory<AudioDebugRecordingManager> weak_factory_; base::WeakPtrFactory<AudioDebugRecordingManager> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(AudioDebugRecordingManager); DISALLOW_COPY_AND_ASSIGN(AudioDebugRecordingManager);
......
...@@ -50,9 +50,9 @@ struct ScopedExpectEnableAfterCreateHelper { ...@@ -50,9 +50,9 @@ struct ScopedExpectEnableAfterCreateHelper {
}; };
// Function bound and passed to AudioDebugRecordingManager::EnableDebugRecording // Function bound and passed to AudioDebugRecordingManager::EnableDebugRecording
// as AudioDebugRecordingManager::CreateFileCallback. // as AudioDebugRecordingManager::CreateWavFileCallback.
void CreateFile(const base::FilePath& file_path, void CreateWavFile(const base::FilePath& file_path,
base::OnceCallback<void(base::File)>) {} base::OnceCallback<void(base::File)>) {}
} // namespace } // namespace
...@@ -78,7 +78,7 @@ class MockAudioDebugRecordingHelper : public AudioDebugRecordingHelper { ...@@ -78,7 +78,7 @@ class MockAudioDebugRecordingHelper : public AudioDebugRecordingHelper {
MOCK_METHOD1(DoEnableDebugRecording, void(const base::FilePath&)); MOCK_METHOD1(DoEnableDebugRecording, void(const base::FilePath&));
void EnableDebugRecording(const base::FilePath& file_name_suffix, void EnableDebugRecording(const base::FilePath& file_name_suffix,
AudioDebugRecordingHelper::CreateFileCallback AudioDebugRecordingHelper::CreateWavFileCallback
create_file_callback) override { create_file_callback) override {
DoEnableDebugRecording(file_name_suffix); DoEnableDebugRecording(file_name_suffix);
} }
...@@ -147,10 +147,10 @@ class AudioDebugRecordingManagerTest : public ::testing::Test { ...@@ -147,10 +147,10 @@ class AudioDebugRecordingManagerTest : public ::testing::Test {
int AudioDebugRecordingManagerTest::expected_next_source_id_ = 1; int AudioDebugRecordingManagerTest::expected_next_source_id_ = 1;
// Shouldn't do anything but store the CreateFileCallback, i.e. no calls to // Shouldn't do anything but store the CreateWavFileCallback, i.e. no calls to
// recorders. // recorders.
TEST_F(AudioDebugRecordingManagerTest, EnableDisable) { TEST_F(AudioDebugRecordingManagerTest, EnableDisable) {
manager_.EnableDebugRecording(base::BindRepeating(&CreateFile)); manager_.EnableDebugRecording(base::BindRepeating(&CreateWavFile));
manager_.DisableDebugRecording(); manager_.DisableDebugRecording();
} }
...@@ -197,7 +197,7 @@ TEST_F(AudioDebugRecordingManagerTest, RegisterEnableDisable) { ...@@ -197,7 +197,7 @@ TEST_F(AudioDebugRecordingManagerTest, RegisterEnableDisable) {
EXPECT_CALL(*mock_recording_helper, DisableDebugRecording()); EXPECT_CALL(*mock_recording_helper, DisableDebugRecording());
} }
manager_.EnableDebugRecording(base::BindRepeating(&CreateFile)); manager_.EnableDebugRecording(base::BindRepeating(&CreateWavFile));
manager_.DisableDebugRecording(); manager_.DisableDebugRecording();
} }
...@@ -210,7 +210,7 @@ TEST_F(AudioDebugRecordingManagerTest, RegisterEnableDisable) { ...@@ -210,7 +210,7 @@ TEST_F(AudioDebugRecordingManagerTest, RegisterEnableDisable) {
TEST_F(AudioDebugRecordingManagerTest, EnableRegisterDisable) { TEST_F(AudioDebugRecordingManagerTest, EnableRegisterDisable) {
ScopedExpectEnableAfterCreateHelper scoped_enable_after_create_helper; ScopedExpectEnableAfterCreateHelper scoped_enable_after_create_helper;
manager_.EnableDebugRecording(base::BindRepeating(&CreateFile)); manager_.EnableDebugRecording(base::BindRepeating(&CreateWavFile));
const AudioParameters params; const AudioParameters params;
std::vector<std::unique_ptr<AudioDebugRecorder>> recorders; std::vector<std::unique_ptr<AudioDebugRecorder>> recorders;
......
...@@ -5,24 +5,16 @@ ...@@ -5,24 +5,16 @@
#ifndef MEDIA_AUDIO_AUDIO_DEBUG_RECORDING_SESSION_H_ #ifndef MEDIA_AUDIO_AUDIO_DEBUG_RECORDING_SESSION_H_
#define MEDIA_AUDIO_AUDIO_DEBUG_RECORDING_SESSION_H_ #define MEDIA_AUDIO_AUDIO_DEBUG_RECORDING_SESSION_H_
#include <memory>
#include "base/macros.h" #include "base/macros.h"
#include "media/base/media_export.h" #include "media/base/media_export.h"
namespace base {
class FilePath;
}
namespace media { namespace media {
// Creating/Destroying an AudioDebugRecordingSession object enables/disables // Enables/disables audio debug recording on construction/destruction. Objects
// audio debug recording. // are created using audio::CreateAudioDebugRecordingSession.
class MEDIA_EXPORT AudioDebugRecordingSession { class MEDIA_EXPORT AudioDebugRecordingSession {
public: public:
virtual ~AudioDebugRecordingSession(); virtual ~AudioDebugRecordingSession() = default;
static std::unique_ptr<AudioDebugRecordingSession> Create(
const base::FilePath& debug_recording_file_path);
protected: protected:
AudioDebugRecordingSession() = default; AudioDebugRecordingSession() = default;
......
...@@ -23,9 +23,11 @@ namespace media { ...@@ -23,9 +23,11 @@ namespace media {
namespace { namespace {
void CreateFile(const base::FilePath& debug_recording_file_path, const base::FilePath::CharType kWavExtension[] = FILE_PATH_LITERAL("wav");
const base::FilePath& file_name_suffix,
base::OnceCallback<void(base::File)> reply_callback) { void CreateWavFile(const base::FilePath& debug_recording_file_path,
const base::FilePath& file_name_suffix,
base::OnceCallback<void(base::File)> reply_callback) {
base::PostTaskWithTraitsAndReplyWithResult( base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE, FROM_HERE,
{base::MayBlock(), base::TaskPriority::BACKGROUND, {base::MayBlock(), base::TaskPriority::BACKGROUND,
...@@ -35,7 +37,8 @@ void CreateFile(const base::FilePath& debug_recording_file_path, ...@@ -35,7 +37,8 @@ void CreateFile(const base::FilePath& debug_recording_file_path,
return base::File(file_name, base::File::FLAG_CREATE_ALWAYS | return base::File(file_name, base::File::FLAG_CREATE_ALWAYS |
base::File::FLAG_WRITE); base::File::FLAG_WRITE);
}, },
debug_recording_file_path.AddExtension(file_name_suffix.value())), debug_recording_file_path.AddExtension(file_name_suffix.value())
.AddExtension(kWavExtension)),
std::move(reply_callback)); std::move(reply_callback));
} }
...@@ -51,7 +54,7 @@ AudioDebugRecordingSessionImpl::AudioDebugRecordingSessionImpl( ...@@ -51,7 +54,7 @@ AudioDebugRecordingSessionImpl::AudioDebugRecordingSessionImpl(
FROM_HERE, FROM_HERE,
base::BindOnce( base::BindOnce(
[](AudioManager* manager, [](AudioManager* manager,
AudioDebugRecordingManager::CreateFileCallback AudioDebugRecordingManager::CreateWavFileCallback
create_file_callback) { create_file_callback) {
AudioDebugRecordingManager* debug_recording_manager = AudioDebugRecordingManager* debug_recording_manager =
manager->GetAudioDebugRecordingManager(); manager->GetAudioDebugRecordingManager();
...@@ -61,7 +64,7 @@ AudioDebugRecordingSessionImpl::AudioDebugRecordingSessionImpl( ...@@ -61,7 +64,7 @@ AudioDebugRecordingSessionImpl::AudioDebugRecordingSessionImpl(
std::move(create_file_callback)); std::move(create_file_callback));
}, },
base::Unretained(audio_manager), base::Unretained(audio_manager),
base::BindRepeating(&CreateFile, debug_recording_file_path))); base::BindRepeating(&CreateWavFile, debug_recording_file_path)));
} }
AudioDebugRecordingSessionImpl::~AudioDebugRecordingSessionImpl() { AudioDebugRecordingSessionImpl::~AudioDebugRecordingSessionImpl() {
......
...@@ -10,11 +10,10 @@ ...@@ -10,11 +10,10 @@
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h" #include "base/files/scoped_temp_dir.h"
#include "base/test/scoped_task_environment.h" #include "base/test/scoped_task_environment.h"
#include "media/audio/audio_debug_recording_test.h"
#include "media/audio/mock_audio_debug_recording_manager.h" #include "media/audio/mock_audio_debug_recording_manager.h"
#include "media/audio/mock_audio_manager.h" #include "media/audio/mock_audio_manager.h"
#include "media/audio/test_audio_thread.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media { namespace media {
...@@ -22,10 +21,11 @@ namespace { ...@@ -22,10 +21,11 @@ namespace {
const base::FilePath::CharType kBaseFileName[] = const base::FilePath::CharType kBaseFileName[] =
FILE_PATH_LITERAL("debug_recording"); FILE_PATH_LITERAL("debug_recording");
const base::FilePath::CharType kWavExtension[] = FILE_PATH_LITERAL("wav");
const base::FilePath::CharType kInputFileNameSuffix[] = const base::FilePath::CharType kInputFileNameSuffix[] =
FILE_PATH_LITERAL("input.1.wav"); FILE_PATH_LITERAL("input.1");
const base::FilePath::CharType kOutputFileNameSuffix[] = const base::FilePath::CharType kOutputFileNameSuffix[] =
FILE_PATH_LITERAL("output.1.wav"); FILE_PATH_LITERAL("output.1");
void OnFileCreated(base::File debug_file) {} void OnFileCreated(base::File debug_file) {}
...@@ -33,8 +33,7 @@ void OnFileCreated(base::File debug_file) {} ...@@ -33,8 +33,7 @@ void OnFileCreated(base::File debug_file) {}
// MockAudioDebugRecordingManager::EnableDebugRecording mocked method to test // MockAudioDebugRecordingManager::EnableDebugRecording mocked method to test
// |create_file_callback| behavior. // |create_file_callback| behavior.
void CreateInputOutputDebugRecordingFiles( void CreateInputOutputDebugRecordingFiles(
const base::RepeatingCallback<void(const base::FilePath&, const AudioDebugRecordingManager::CreateWavFileCallback&
base::OnceCallback<void(base::File)>)>&
create_file_callback) { create_file_callback) {
create_file_callback.Run(base::FilePath(kInputFileNameSuffix), create_file_callback.Run(base::FilePath(kInputFileNameSuffix),
base::BindOnce(&OnFileCreated)); base::BindOnce(&OnFileCreated));
...@@ -44,29 +43,11 @@ void CreateInputOutputDebugRecordingFiles( ...@@ -44,29 +43,11 @@ void CreateInputOutputDebugRecordingFiles(
} // namespace } // namespace
class AudioDebugRecordingSessionImplTest : public testing::Test { class AudioDebugRecordingSessionImplTest : public AudioDebugRecordingTest {
public: public:
AudioDebugRecordingSessionImplTest() { SetBaseFilePath(); } AudioDebugRecordingSessionImplTest() { SetBaseFilePath(); }
protected: protected:
void CreateAudioManager() {
mock_audio_manager_ =
std::make_unique<MockAudioManager>(std::make_unique<TestAudioThread>());
ASSERT_NE(nullptr, AudioManager::Get());
ASSERT_EQ(static_cast<AudioManager*>(mock_audio_manager_.get()),
AudioManager::Get());
}
void ShutdownAudioManager() { ASSERT_TRUE(mock_audio_manager_->Shutdown()); }
void InitializeAudioDebugRecordingManager() {
mock_audio_manager_->InitializeDebugRecording();
mock_debug_recording_manager_ =
static_cast<MockAudioDebugRecordingManager*>(
mock_audio_manager_->GetAudioDebugRecordingManager());
ASSERT_NE(nullptr, mock_debug_recording_manager_);
}
void CreateDebugRecordingSession() { void CreateDebugRecordingSession() {
audio_debug_recording_session_impl_ = audio_debug_recording_session_impl_ =
std::make_unique<media::AudioDebugRecordingSessionImpl>( std::make_unique<media::AudioDebugRecordingSessionImpl>(
...@@ -77,11 +58,6 @@ class AudioDebugRecordingSessionImplTest : public testing::Test { ...@@ -77,11 +58,6 @@ class AudioDebugRecordingSessionImplTest : public testing::Test {
audio_debug_recording_session_impl_.reset(); audio_debug_recording_session_impl_.reset();
} }
base::test::ScopedTaskEnvironment scoped_task_environment_;
std::unique_ptr<MockAudioManager> mock_audio_manager_;
MockAudioDebugRecordingManager* mock_debug_recording_manager_;
std::unique_ptr<AudioDebugRecordingSessionImpl>
audio_debug_recording_session_impl_;
base::FilePath base_file_path_; base::FilePath base_file_path_;
private: private:
...@@ -91,6 +67,8 @@ class AudioDebugRecordingSessionImplTest : public testing::Test { ...@@ -91,6 +67,8 @@ class AudioDebugRecordingSessionImplTest : public testing::Test {
} }
base::ScopedTempDir temp_dir_; base::ScopedTempDir temp_dir_;
std::unique_ptr<AudioDebugRecordingSessionImpl>
audio_debug_recording_session_impl_;
DISALLOW_COPY_AND_ASSIGN(AudioDebugRecordingSessionImplTest); DISALLOW_COPY_AND_ASSIGN(AudioDebugRecordingSessionImplTest);
}; };
...@@ -125,9 +103,9 @@ TEST_F(AudioDebugRecordingSessionImplTest, ...@@ -125,9 +103,9 @@ TEST_F(AudioDebugRecordingSessionImplTest,
ShutdownAudioManager(); ShutdownAudioManager();
} }
// Tests the CreateFile method from AudioDebugRecordingSessionImpl unnamed // Tests the CreateWavFile method from AudioDebugRecordingSessionImpl unnamed
// namespace. // namespace.
TEST_F(AudioDebugRecordingSessionImplTest, CreateFileCreatesExpectedFiles) { TEST_F(AudioDebugRecordingSessionImplTest, CreateWavFileCreatesExpectedFiles) {
CreateAudioManager(); CreateAudioManager();
InitializeAudioDebugRecordingManager(); InitializeAudioDebugRecordingManager();
EXPECT_CALL(*mock_debug_recording_manager_, EnableDebugRecording(testing::_)) EXPECT_CALL(*mock_debug_recording_manager_, EnableDebugRecording(testing::_))
...@@ -139,9 +117,11 @@ TEST_F(AudioDebugRecordingSessionImplTest, CreateFileCreatesExpectedFiles) { ...@@ -139,9 +117,11 @@ TEST_F(AudioDebugRecordingSessionImplTest, CreateFileCreatesExpectedFiles) {
// Check that expected files were created. // Check that expected files were created.
base::FilePath input_recording_filename( base::FilePath input_recording_filename(
base_file_path_.AddExtension(kInputFileNameSuffix)); base_file_path_.AddExtension(kInputFileNameSuffix)
.AddExtension(kWavExtension));
base::FilePath output_recording_filename( base::FilePath output_recording_filename(
base_file_path_.AddExtension(kOutputFileNameSuffix)); base_file_path_.AddExtension(kOutputFileNameSuffix)
.AddExtension(kWavExtension));
EXPECT_TRUE(base::PathExists(output_recording_filename)); EXPECT_TRUE(base::PathExists(output_recording_filename));
EXPECT_TRUE(base::PathExists(input_recording_filename)); EXPECT_TRUE(base::PathExists(input_recording_filename));
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/audio/audio_debug_recording_test.h"
#include "media/audio/mock_audio_debug_recording_manager.h"
#include "media/audio/mock_audio_manager.h"
#include "media/audio/test_audio_thread.h"
namespace media {
AudioDebugRecordingTest::AudioDebugRecordingTest() = default;
AudioDebugRecordingTest::~AudioDebugRecordingTest() = default;
void AudioDebugRecordingTest::CreateAudioManager() {
DCHECK(AudioManager::Get() == nullptr);
mock_audio_manager_ =
std::make_unique<MockAudioManager>(std::make_unique<TestAudioThread>());
ASSERT_NE(nullptr, AudioManager::Get());
ASSERT_EQ(static_cast<AudioManager*>(mock_audio_manager_.get()),
AudioManager::Get());
}
void AudioDebugRecordingTest::ShutdownAudioManager() {
DCHECK(mock_audio_manager_);
ASSERT_TRUE(mock_audio_manager_->Shutdown());
}
void AudioDebugRecordingTest::InitializeAudioDebugRecordingManager() {
DCHECK(mock_audio_manager_);
mock_audio_manager_->InitializeDebugRecording();
mock_debug_recording_manager_ = static_cast<MockAudioDebugRecordingManager*>(
mock_audio_manager_->GetAudioDebugRecordingManager());
ASSERT_NE(nullptr, mock_debug_recording_manager_);
}
} // namespace media
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_AUDIO_AUDIO_DEBUG_RECORDING_TEST_H_
#define MEDIA_AUDIO_AUDIO_DEBUG_RECORDING_TEST_H_
#include <memory>
#include "base/test/scoped_task_environment.h"
#include "media/base/media_export.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media {
class MockAudioDebugRecordingManager;
class MockAudioManager;
// Base test class for media/audio/ and services/audio/ debug recording test
// classes.
class AudioDebugRecordingTest : public testing::Test {
public:
AudioDebugRecordingTest();
~AudioDebugRecordingTest() override;
protected:
void CreateAudioManager();
void ShutdownAudioManager();
void InitializeAudioDebugRecordingManager();
base::test::ScopedTaskEnvironment scoped_task_environment_;
std::unique_ptr<MockAudioManager> mock_audio_manager_;
MockAudioDebugRecordingManager* mock_debug_recording_manager_;
private:
DISALLOW_COPY_AND_ASSIGN(AudioDebugRecordingTest);
};
} // namespace media
#endif // MEDIA_AUDIO_AUDIO_DEBUG_RECORDING_TEST_H_
...@@ -15,6 +15,8 @@ service_manifest("manifest") { ...@@ -15,6 +15,8 @@ service_manifest("manifest") {
source_set("lib") { source_set("lib") {
sources = [ sources = [
"debug_recording.cc",
"debug_recording.h",
"in_process_audio_manager_accessor.cc", "in_process_audio_manager_accessor.cc",
"in_process_audio_manager_accessor.h", "in_process_audio_manager_accessor.h",
"service.cc", "service.cc",
...@@ -37,7 +39,9 @@ source_set("tests") { ...@@ -37,7 +39,9 @@ source_set("tests") {
testonly = true testonly = true
sources = [ sources = [
"debug_recording_unittest.cc",
"test/audio_system_to_service_adapter_test.cc", "test/audio_system_to_service_adapter_test.cc",
"test/debug_recording_session_unittest.cc",
"test/in_process_service_test.cc", "test/in_process_service_test.cc",
] ]
...@@ -50,6 +54,7 @@ source_set("tests") { ...@@ -50,6 +54,7 @@ source_set("tests") {
"//services/audio/public/mojom", "//services/audio/public/mojom",
"//services/service_manager/public/cpp", "//services/service_manager/public/cpp",
"//services/service_manager/public/cpp:service_test_support", "//services/service_manager/public/cpp:service_test_support",
"//services/service_manager/public/cpp/test:test_support",
"//testing/gmock", "//testing/gmock",
"//testing/gtest", "//testing/gtest",
] ]
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/audio/debug_recording.h"
#include <memory>
#include <utility>
#include "media/audio/audio_debug_recording_manager.h"
#include "media/audio/audio_manager.h"
namespace audio {
DebugRecording::DebugRecording(mojom::DebugRecordingRequest request,
media::AudioManager* audio_manager)
: binding_(this, std::move(request)),
audio_manager_(audio_manager),
weak_factory_(this) {
DCHECK(audio_manager_ != nullptr);
DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
// On connection error debug recording is disabled, but object is not
// destroyed, it will be cleaned-up by service either on next bind request on
// or when service is shut down.
binding_.set_connection_error_handler(
base::BindOnce(&DebugRecording::Disable, base::Unretained(this)));
}
DebugRecording::~DebugRecording() {
Disable();
}
void DebugRecording::Enable(
mojom::DebugRecordingFileProviderPtr recording_file_provider) {
DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
DCHECK(!IsEnabled());
file_provider_ = std::move(recording_file_provider);
media::AudioDebugRecordingManager* debug_recording_manager =
audio_manager_->GetAudioDebugRecordingManager();
if (debug_recording_manager == nullptr)
return;
debug_recording_manager->EnableDebugRecording(base::BindRepeating(
&DebugRecording::CreateWavFile, weak_factory_.GetWeakPtr()));
}
void DebugRecording::Disable() {
DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
if (!IsEnabled())
return;
file_provider_.reset();
binding_.Close();
media::AudioDebugRecordingManager* debug_recording_manager =
audio_manager_->GetAudioDebugRecordingManager();
if (debug_recording_manager == nullptr)
return;
debug_recording_manager->DisableDebugRecording();
}
void DebugRecording::CreateWavFile(
const base::FilePath& file_suffix,
mojom::DebugRecordingFileProvider::CreateWavFileCallback reply_callback) {
DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
file_provider_->CreateWavFile(file_suffix, std::move(reply_callback));
}
bool DebugRecording::IsEnabled() {
DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
return file_provider_.is_bound();
}
} // namespace audio
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SERVICES_AUDIO_DEBUG_RECORDING_H_
#define SERVICES_AUDIO_DEBUG_RECORDING_H_
#include <utility>
#include "base/memory/weak_ptr.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "services/audio/public/mojom/debug_recording.mojom.h"
namespace media {
class AudioManager;
}
namespace audio {
// Implementation for controlling audio debug recording.
class DebugRecording : public mojom::DebugRecording {
public:
DebugRecording(mojom::DebugRecordingRequest request,
media::AudioManager* audio_manager);
// Disables audio debug recording if Enable() was called before.
~DebugRecording() override;
// Enables audio debug recording.
void Enable(mojom::DebugRecordingFileProviderPtr file_provider) override;
private:
// Called on binding connection error.
void Disable();
void CreateWavFile(
const base::FilePath& file_suffix,
mojom::DebugRecordingFileProvider::CreateWavFileCallback reply_callback);
bool IsEnabled();
mojo::Binding<mojom::DebugRecording> binding_;
mojom::DebugRecordingFileProviderPtr file_provider_;
media::AudioManager* const audio_manager_;
base::WeakPtrFactory<DebugRecording> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(DebugRecording);
};
} // namespace audio
#endif // SERVICES_AUDIO_DEBUG_RECORDING_H_
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/audio/debug_recording.h"
#include <memory>
#include "base/files/file_path.h"
#include "base/test/scoped_task_environment.h"
#include "media/audio/audio_debug_recording_test.h"
#include "media/audio/mock_audio_debug_recording_manager.h"
#include "media/audio/mock_audio_manager.h"
#include "services/audio/public/cpp/debug_recording_session.h"
#include "services/audio/public/mojom/debug_recording.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace audio {
namespace {
const base::FilePath::CharType kBaseFileName[] =
FILE_PATH_LITERAL("base_file_name");
}
class DebugRecordingTest : public media::AudioDebugRecordingTest {
public:
DebugRecordingTest() = default;
~DebugRecordingTest() override = default;
void SetUp() override {
CreateAudioManager();
InitializeAudioDebugRecordingManager();
}
void TearDown() override { ShutdownAudioManager(); }
protected:
void CreateDebugRecording() {
debug_recording_ = std::make_unique<DebugRecording>(
mojo::MakeRequest(&debug_recording_ptr_),
static_cast<media::AudioManager*>(mock_audio_manager_.get()));
EXPECT_TRUE(debug_recording_ptr_.is_bound());
}
void EnableDebugRecording() {
mojom::DebugRecordingFileProviderPtr file_provider_ptr;
DebugRecordingSession::DebugRecordingFileProvider file_provider(
mojo::MakeRequest(&file_provider_ptr), base::FilePath(kBaseFileName));
ASSERT_TRUE(file_provider_ptr.is_bound());
debug_recording_ptr_->Enable(std::move(file_provider_ptr));
}
void DestroyDebugRecording() { debug_recording_ptr_.reset(); }
MOCK_METHOD0(OnConnectionError, void());
private:
std::unique_ptr<DebugRecording> debug_recording_;
mojom::DebugRecordingPtr debug_recording_ptr_;
DISALLOW_COPY_AND_ASSIGN(DebugRecordingTest);
};
TEST_F(DebugRecordingTest, EnableResetEnablesDisablesDebugRecording) {
CreateDebugRecording();
EXPECT_CALL(*mock_debug_recording_manager_, EnableDebugRecording(testing::_));
EnableDebugRecording();
EXPECT_CALL(*mock_debug_recording_manager_, DisableDebugRecording());
DestroyDebugRecording();
}
TEST_F(DebugRecordingTest, ResetWithoutEnableDoesNotDisableDebugRecording) {
CreateDebugRecording();
EXPECT_CALL(*mock_debug_recording_manager_, DisableDebugRecording()).Times(0);
DestroyDebugRecording();
}
} // namespace audio
...@@ -5,7 +5,8 @@ ...@@ -5,7 +5,8 @@
"interface_provider_specs": { "interface_provider_specs": {
"service_manager:connector": { "service_manager:connector": {
"provides": { "provides": {
"info": [ "audio::mojom::SystemInfo" ] "info": [ "audio::mojom::SystemInfo" ],
"debug_recording": [ "audio::mojom::DebugRecording" ]
}, },
"requires": { "requires": {
"service_manager": [ "service_manager:all_users" ] "service_manager": [ "service_manager:all_users" ]
......
...@@ -8,6 +8,10 @@ source_set("cpp") { ...@@ -8,6 +8,10 @@ source_set("cpp") {
"audio_system_factory.h", "audio_system_factory.h",
"audio_system_to_service_adapter.cc", "audio_system_to_service_adapter.cc",
"audio_system_to_service_adapter.h", "audio_system_to_service_adapter.h",
"debug_recording_session.cc",
"debug_recording_session.h",
"debug_recording_session_factory.cc",
"debug_recording_session_factory.h",
] ]
public_deps = [ public_deps = [
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/audio/public/cpp/debug_recording_session.h"
#include <utility>
#include "base/files/file_path.h"
#include "media/audio/audio_debug_recording_manager.h"
#include "media/audio/audio_manager.h"
#include "services/audio/public/mojom/constants.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
namespace audio {
namespace {
const base::FilePath::CharType kWavExtension[] = FILE_PATH_LITERAL("wav");
}
DebugRecordingSession::DebugRecordingFileProvider::DebugRecordingFileProvider(
mojom::DebugRecordingFileProviderRequest request,
const base::FilePath& file_name_base)
: binding_(this, std::move(request)), file_name_base_(file_name_base) {}
DebugRecordingSession::DebugRecordingFileProvider::
~DebugRecordingFileProvider() = default;
void DebugRecordingSession::DebugRecordingFileProvider::CreateWavFile(
const base::FilePath& file_name_suffix,
CreateWavFileCallback reply_callback) {
base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE,
{base::MayBlock(), base::TaskPriority::BACKGROUND,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
base::BindOnce(
[](const base::FilePath& file_name) {
return base::File(file_name, base::File::FLAG_CREATE_ALWAYS |
base::File::FLAG_WRITE);
},
file_name_base_.AddExtension(file_name_suffix.value())
.AddExtension(kWavExtension)),
std::move(reply_callback));
}
DebugRecordingSession::DebugRecordingSession(
const base::FilePath& file_name_base,
std::unique_ptr<service_manager::Connector> connector) {
DCHECK(connector);
mojom::DebugRecordingFileProviderPtr file_provider;
file_provider_ = std::make_unique<DebugRecordingFileProvider>(
mojo::MakeRequest(&file_provider), file_name_base);
connector->BindInterface(audio::mojom::kServiceName,
mojo::MakeRequest(&debug_recording_));
if (debug_recording_.is_bound())
debug_recording_->Enable(std::move(file_provider));
}
DebugRecordingSession::~DebugRecordingSession() {}
} // namespace audio
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SERVICES_AUDIO_PUBLIC_CPP_DEBUG_RECORDING_SESSION_H_
#define SERVICES_AUDIO_PUBLIC_CPP_DEBUG_RECORDING_SESSION_H_
#include <memory>
#include "media/audio/audio_debug_recording_session.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "services/audio/public/mojom/debug_recording.mojom.h"
namespace service_manager {
class Connector;
}
namespace base {
class FilePath;
}
namespace audio {
class DebugRecordingFileProvider;
// Client class for using mojom::DebugRecording interface. This class owns
// mojom::DebugRecordingFileProvider implementation, therefore owners of this
// class' instances need permission to create files in |file_name_base| path
// passed in constructor in order to start debug recording. If file creation
// fails, debug recording will silently not start.
class DebugRecordingSession : public media::AudioDebugRecordingSession {
public:
class DebugRecordingFileProvider : public mojom::DebugRecordingFileProvider {
public:
DebugRecordingFileProvider(mojom::DebugRecordingFileProviderRequest request,
const base::FilePath& file_name_base);
~DebugRecordingFileProvider() override;
// Creates file with name "|file_name_base_|.|file_suffix|.wav".
void CreateWavFile(const base::FilePath& file_suffix,
CreateWavFileCallback reply_callback) override;
private:
mojo::Binding<mojom::DebugRecordingFileProvider> binding_;
base::FilePath file_name_base_;
DISALLOW_COPY_AND_ASSIGN(DebugRecordingFileProvider);
};
DebugRecordingSession(const base::FilePath& file_name_base,
std::unique_ptr<service_manager::Connector> connector);
~DebugRecordingSession() override;
private:
std::unique_ptr<DebugRecordingFileProvider> file_provider_;
mojom::DebugRecordingPtr debug_recording_;
DISALLOW_COPY_AND_ASSIGN(DebugRecordingSession);
};
} // namespace audio
#endif // SERVICES_AUDIO_PUBLIC_CPP_DEBUG_RECORDING_SESSION_H_
...@@ -2,19 +2,24 @@ ...@@ -2,19 +2,24 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "media/audio/audio_debug_recording_session.h" #include "services/audio/public/cpp/debug_recording_session_factory.h"
#include <utility>
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "media/audio/audio_debug_recording_session_impl.h" #include "media/audio/audio_debug_recording_session_impl.h"
#include "services/service_manager/public/cpp/connector.h"
namespace media { namespace audio {
AudioDebugRecordingSession::~AudioDebugRecordingSession() {} std::unique_ptr<media::AudioDebugRecordingSession>
CreateAudioDebugRecordingSession(
const base::FilePath& debug_recording_file_path,
std::unique_ptr<service_manager::Connector> connector) {
DCHECK(connector);
std::unique_ptr<AudioDebugRecordingSession> AudioDebugRecordingSession::Create( return std::make_unique<media::AudioDebugRecordingSessionImpl>(
const base::FilePath& debug_recording_file_path) {
return std::make_unique<AudioDebugRecordingSessionImpl>(
debug_recording_file_path); debug_recording_file_path);
} }
} // namespace media } // namespace audio
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SERVICES_AUDIO_PUBLIC_CPP_DEBUG_RECORDING_SESSION_FACTORY_H_
#define SERVICES_AUDIO_PUBLIC_CPP_DEBUG_RECORDING_SESSION_FACTORY_H_
#include <memory>
namespace base {
class FilePath;
}
namespace media {
class AudioDebugRecordingSession;
}
namespace service_manager {
class Connector;
}
namespace audio {
std::unique_ptr<media::AudioDebugRecordingSession>
CreateAudioDebugRecordingSession(
const base::FilePath& debug_recording_file_path,
std::unique_ptr<service_manager::Connector> connector);
} // namespace audio
#endif // SERVICES_AUDIO_PUBLIC_CPP_DEBUG_RECORDING_SESSION_FACTORY_H_
...@@ -7,6 +7,7 @@ import("//mojo/public/tools/bindings/mojom.gni") ...@@ -7,6 +7,7 @@ import("//mojo/public/tools/bindings/mojom.gni")
mojom("mojom") { mojom("mojom") {
sources = [ sources = [
"audio_device_description.mojom", "audio_device_description.mojom",
"debug_recording.mojom",
"system_info.mojom", "system_info.mojom",
] ]
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
module audio.mojom;
import "mojo/common/file.mojom";
import "mojo/common/file_path.mojom";
// Creates audio debug recording files. Requires a base file path at binding.
// All files are created in the path defined in implementation, to which
// ".|suffix|" and ".wav" extension are appended. E.g.: from base file path
// "/path/base_name" and suffix "output.1", "/path/base_name.output.1.wav" will
// be created. This interface is called by audio service from implementation of
// DebugRecording interface defined below.
interface DebugRecordingFileProvider {
// Returns invalid file in case of failure.
CreateWavFile(mojo.common.mojom.FilePath suffix)
=> (mojo.common.mojom.File? file);
};
// Controls audio debug recording. To enable, bind interface and call Enable
// with a bound DebugRecordingFileProvider interface pointer. To disable, close
// debug recording message pipe. Note: only the instance that enabled debug
// recording can disable it, i.e. closing debug recording message pipe without
// priorly enabling debug recording will not change debug recording state.
interface DebugRecording {
Enable(DebugRecordingFileProvider file_provider);
};
...@@ -4,11 +4,14 @@ ...@@ -4,11 +4,14 @@
#include "services/audio/service.h" #include "services/audio/service.h"
#include <utility>
#include "base/logging.h" #include "base/logging.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/single_thread_task_runner.h" #include "base/single_thread_task_runner.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "media/audio/audio_manager.h" #include "media/audio/audio_manager.h"
#include "services/audio/debug_recording.h"
#include "services/audio/system_info.h" #include "services/audio/system_info.h"
#include "services/service_manager/public/cpp/service_context.h" #include "services/service_manager/public/cpp/service_context.h"
...@@ -28,6 +31,8 @@ void Service::OnStart() { ...@@ -28,6 +31,8 @@ void Service::OnStart() {
DVLOG(4) << "audio::Service::OnStart"; DVLOG(4) << "audio::Service::OnStart";
registry_.AddInterface<mojom::SystemInfo>(base::BindRepeating( registry_.AddInterface<mojom::SystemInfo>(base::BindRepeating(
&Service::BindSystemInfoRequest, base::Unretained(this))); &Service::BindSystemInfoRequest, base::Unretained(this)));
registry_.AddInterface<mojom::DebugRecording>(base::BindRepeating(
&Service::BindDebugRecordingRequest, base::Unretained(this)));
} }
void Service::OnBindInterface( void Service::OnBindInterface(
...@@ -35,12 +40,15 @@ void Service::OnBindInterface( ...@@ -35,12 +40,15 @@ void Service::OnBindInterface(
const std::string& interface_name, const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) { mojo::ScopedMessagePipeHandle interface_pipe) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DVLOG(4) << "audio::Service::OnBinfInterface"; DVLOG(4) << "audio::Service::OnBindInterface";
registry_.BindInterface(interface_name, std::move(interface_pipe)); registry_.BindInterface(interface_name, std::move(interface_pipe));
} }
bool Service::OnServiceManagerConnectionLost() { bool Service::OnServiceManagerConnectionLost() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// Reset |debug_recording_| to disable debug recording before AudioManager
// shutdown.
debug_recording_.reset();
audio_manager_accessor_->Shutdown(); audio_manager_accessor_->Shutdown();
return true; return true;
} }
...@@ -56,4 +64,14 @@ void Service::BindSystemInfoRequest(mojom::SystemInfoRequest request) { ...@@ -56,4 +64,14 @@ void Service::BindSystemInfoRequest(mojom::SystemInfoRequest request) {
system_info_->Bind(std::move(request)); system_info_->Bind(std::move(request));
} }
void Service::BindDebugRecordingRequest(mojom::DebugRecordingRequest request) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// Accept only one bind request at a time. Old request is overwritten.
// |debug_recording_| must be reset first to disable debug recording, and then
// create a new DebugRecording instance to enable debug recording.
debug_recording_.reset();
debug_recording_ = std::make_unique<DebugRecording>(
std::move(request), audio_manager_accessor_->GetAudioManager());
}
} // namespace audio } // namespace audio
...@@ -6,10 +6,12 @@ ...@@ -6,10 +6,12 @@
#define SERVICES_AUDIO_SERVICE_H_ #define SERVICES_AUDIO_SERVICE_H_
#include <memory> #include <memory>
#include <string>
#include "base/callback.h" #include "base/callback.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/threading/thread_checker.h" #include "base/threading/thread_checker.h"
#include "services/audio/public/mojom/debug_recording.mojom.h"
#include "services/audio/public/mojom/system_info.mojom.h" #include "services/audio/public/mojom/system_info.mojom.h"
#include "services/service_manager/public/cpp/binder_registry.h" #include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/service.h" #include "services/service_manager/public/cpp/service.h"
...@@ -19,6 +21,7 @@ class AudioManager; ...@@ -19,6 +21,7 @@ class AudioManager;
} // namespace media } // namespace media
namespace audio { namespace audio {
class DebugRecording;
class SystemInfo; class SystemInfo;
class Service : public service_manager::Service { class Service : public service_manager::Service {
...@@ -27,7 +30,7 @@ class Service : public service_manager::Service { ...@@ -27,7 +30,7 @@ class Service : public service_manager::Service {
// its created on, and that thread must be AudioManager main thread. // its created on, and that thread must be AudioManager main thread.
class AudioManagerAccessor { class AudioManagerAccessor {
public: public:
virtual ~AudioManagerAccessor(){}; virtual ~AudioManagerAccessor() {}
// Must be called before destruction. // Must be called before destruction.
virtual void Shutdown() = 0; virtual void Shutdown() = 0;
...@@ -49,9 +52,11 @@ class Service : public service_manager::Service { ...@@ -49,9 +52,11 @@ class Service : public service_manager::Service {
private: private:
void BindSystemInfoRequest(mojom::SystemInfoRequest request); void BindSystemInfoRequest(mojom::SystemInfoRequest request);
void BindDebugRecordingRequest(mojom::DebugRecordingRequest request);
std::unique_ptr<AudioManagerAccessor> audio_manager_accessor_; std::unique_ptr<AudioManagerAccessor> audio_manager_accessor_;
std::unique_ptr<SystemInfo> system_info_; std::unique_ptr<SystemInfo> system_info_;
std::unique_ptr<DebugRecording> debug_recording_;
service_manager::BinderRegistry registry_; service_manager::BinderRegistry registry_;
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/audio/public/cpp/debug_recording_session.h"
#include <memory>
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/test/scoped_task_environment.h"
#include "media/audio/audio_debug_recording_test.h"
#include "media/audio/mock_audio_debug_recording_manager.h"
#include "media/audio/mock_audio_manager.h"
#include "services/audio/service_factory.h"
#include "services/service_manager/public/cpp/service_test.h"
#include "services/service_manager/public/cpp/test/test_connector_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace audio {
namespace {
const base::FilePath::CharType kBaseFileName[] =
FILE_PATH_LITERAL("debug_recording");
const base::FilePath::CharType kWavExtension[] = FILE_PATH_LITERAL("wav");
const base::FilePath::CharType kValidSuffix[] = FILE_PATH_LITERAL("output.1");
const base::FilePath::CharType kEmptySuffix[] = FILE_PATH_LITERAL("");
const base::FilePath::CharType kInvalidSuffix[] =
FILE_PATH_LITERAL("/../invalid");
} // namespace
class DebugRecordingFileProviderTest : public testing::Test {
public:
DebugRecordingFileProviderTest() = default;
~DebugRecordingFileProviderTest() override = default;
void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
file_path_ = temp_dir_.GetPath().Append(kBaseFileName);
file_provider_ =
std::make_unique<DebugRecordingSession::DebugRecordingFileProvider>(
mojo::MakeRequest(&file_provider_ptr_), file_path_);
ASSERT_TRUE(file_provider_ptr_.is_bound());
}
void TearDown() override { file_provider_.reset(); }
base::FilePath GetFileName(base::FilePath suffix) {
return file_path_.AddExtension(suffix.value()).AddExtension(kWavExtension);
}
MOCK_METHOD1(OnFileCreated, void(bool));
void FileCreated(base::File file) { OnFileCreated(file.IsValid()); }
protected:
mojom::DebugRecordingFileProviderPtr file_provider_ptr_;
base::test::ScopedTaskEnvironment scoped_task_environment_;
private:
std::unique_ptr<DebugRecordingSession::DebugRecordingFileProvider>
file_provider_;
base::ScopedTempDir temp_dir_;
base::FilePath file_path_;
DISALLOW_COPY_AND_ASSIGN(DebugRecordingFileProviderTest);
};
class DebugRecordingSessionTest : public media::AudioDebugRecordingTest {
public:
DebugRecordingSessionTest() = default;
~DebugRecordingSessionTest() override = default;
void SetUp() override {
CreateAudioManager();
InitializeAudioDebugRecordingManager();
connector_factory_ =
service_manager::TestConnectorFactory::CreateForUniqueService(
CreateEmbeddedService(
static_cast<media::AudioManager*>(mock_audio_manager_.get())));
scoped_task_environment_.RunUntilIdle();
}
void TearDown() override { ShutdownAudioManager(); }
protected:
std::unique_ptr<DebugRecordingSession> CreateDebugRecordingSession() {
std::unique_ptr<DebugRecordingSession> session(
std::make_unique<DebugRecordingSession>(
base::FilePath(kBaseFileName),
connector_factory_->CreateConnector()));
scoped_task_environment_.RunUntilIdle();
return session;
}
void DestroyDebugRecordingSession(
std::unique_ptr<DebugRecordingSession> debug_recording_session) {
debug_recording_session.reset();
scoped_task_environment_.RunUntilIdle();
}
private:
std::unique_ptr<service_manager::TestConnectorFactory> connector_factory_;
DISALLOW_COPY_AND_ASSIGN(DebugRecordingSessionTest);
};
TEST_F(DebugRecordingFileProviderTest, CreateWithValidSuffixReturnsValidFile) {
base::FilePath suffix(kValidSuffix);
EXPECT_CALL(*this, OnFileCreated(true));
file_provider_ptr_->CreateWavFile(
suffix, base::BindOnce(&DebugRecordingFileProviderTest::FileCreated,
base::Unretained(this)));
scoped_task_environment_.RunUntilIdle();
base::FilePath file_name(GetFileName(suffix));
EXPECT_TRUE(base::PathExists(file_name));
ASSERT_TRUE(base::DeleteFile(file_name, false));
}
TEST_F(DebugRecordingFileProviderTest, CreateWithEmptySuffixReturnsValidFile) {
base::FilePath suffix(kEmptySuffix);
EXPECT_CALL(*this, OnFileCreated(true));
file_provider_ptr_->CreateWavFile(
suffix, base::BindOnce(&DebugRecordingFileProviderTest::FileCreated,
base::Unretained(this)));
scoped_task_environment_.RunUntilIdle();
base::FilePath file_name(GetFileName(suffix));
EXPECT_TRUE(base::PathExists(file_name));
ASSERT_TRUE(base::DeleteFile(file_name, false));
}
TEST_F(DebugRecordingFileProviderTest,
CreateWithInvalidSuffixReturnsInvalidFile) {
base::FilePath suffix(kInvalidSuffix);
EXPECT_CALL(*this, OnFileCreated(false));
file_provider_ptr_->CreateWavFile(
suffix, base::BindOnce(&DebugRecordingFileProviderTest::FileCreated,
base::Unretained(this)));
scoped_task_environment_.RunUntilIdle();
EXPECT_FALSE(base::PathExists(GetFileName(suffix)));
}
TEST_F(DebugRecordingSessionTest,
CreateDestroySessionEnablesDisablesDebugRecording) {
EXPECT_CALL(*mock_debug_recording_manager_, EnableDebugRecording(testing::_));
std::unique_ptr<DebugRecordingSession> session =
CreateDebugRecordingSession();
EXPECT_CALL(*mock_debug_recording_manager_, DisableDebugRecording());
DestroyDebugRecordingSession(std::move(session));
}
TEST_F(DebugRecordingSessionTest,
CreateTwoSessionsFirstSessionDestroyedOnSecondSessionCreation) {
testing::InSequence seq;
EXPECT_CALL(*mock_debug_recording_manager_, EnableDebugRecording(testing::_));
std::unique_ptr<DebugRecordingSession> first_session =
CreateDebugRecordingSession();
EXPECT_CALL(*mock_debug_recording_manager_, DisableDebugRecording());
EXPECT_CALL(*mock_debug_recording_manager_, EnableDebugRecording(testing::_));
std::unique_ptr<DebugRecordingSession> second_session =
CreateDebugRecordingSession();
EXPECT_CALL(*mock_debug_recording_manager_, DisableDebugRecording()).Times(0);
DestroyDebugRecordingSession(std::move(first_session));
EXPECT_CALL(*mock_debug_recording_manager_, DisableDebugRecording());
DestroyDebugRecordingSession(std::move(second_session));
}
} // namespace audio
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment