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

Add UserInputMonitor in audio service.

audio::UserInputMonitor overrides audio::UserInputMonitor::GetKeyPressCount() to read key press
count (computed in browser process) from shared memory. Read only handle to key press count shmem
is passed over IPC on audio service input stream creation.

Design doc: https://docs.google.com/document/d/1GHL4uMlIFox2eAqsjUQVA8eJ7HYU3g2AoyAqyx3pxMA/edit?usp=sharing

Notes:
- Browser side implementation of key press count share memory, and  wrapping of memory handle
  into a Mojo handle will be added in dependent CL https://crrev.com/c/1025754.
- UserInputMonitor is enabled in MojoAudioInputStreamObserver constructor, when a stream is created,
  and disabled on connection error, called when the observed stream is destroyed.
- audio:: and media:: UserInputMonitor implementations inherit from media::UserInputMonitorBase in
  order to keep media::AudioInputController unchanged for now. Inheritance will be removed when
  switching to audio service input streams.

Streams design diagram: http://drawings/1_ZIKj6lihGKRjq4Mflduitmkn_REqpHFeqVNelBGHHk

Bug: 828864
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel
Change-Id: I0219494d73df2fd275d2b7ccb5bf01f81a1ff11c
Reviewed-on: https://chromium-review.googlesource.com/1011605
Commit-Queue: Marina Ciocea <marinaciocea@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Reviewed-by: default avatarDale Curtis <dalecurtis@chromium.org>
Reviewed-by: default avatarOlga Sharonova <olka@chromium.org>
Reviewed-by: default avatarMax Morin <maxmorin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#553967}
parent 6c2e15ce
......@@ -105,7 +105,7 @@ class MockEventHandler : public media::AudioInputDelegate::EventHandler {
MOCK_METHOD1(OnStreamError, void(int));
};
class MockUserInputMonitor : public media::UserInputMonitor {
class MockUserInputMonitor : public media::UserInputMonitorBase {
public:
MockUserInputMonitor() {}
......
......@@ -83,7 +83,7 @@ class MockSyncWriter : public AudioInputController::SyncWriter {
MOCK_METHOD0(Close, void());
};
class MockUserInputMonitor : public UserInputMonitor {
class MockUserInputMonitor : public UserInputMonitorBase {
public:
MockUserInputMonitor() = default;
......
......@@ -4,38 +4,66 @@
#include "media/base/user_input_monitor.h"
#include "base/atomicops.h"
#include "base/logging.h"
namespace media {
uint32_t ReadKeyPressMonitorCount(
const base::ReadOnlySharedMemoryMapping& shmem_mapping) {
if (!shmem_mapping.IsValid())
return 0;
// No ordering constraints between Load/Store operations, a temporary
// inconsistent value is fine.
return base::subtle::NoBarrier_Load(
reinterpret_cast<const base::subtle::Atomic32*>(shmem_mapping.memory()));
}
void WriteKeyPressMonitorCount(
const base::WritableSharedMemoryMapping& shmem_mapping,
uint32_t count) {
if (!shmem_mapping.IsValid())
return;
// No ordering constraints between Load/Store operations, a temporary
// inconsistent value is fine.
base::subtle::NoBarrier_Store(
reinterpret_cast<base::subtle::Atomic32*>(shmem_mapping.memory()), count);
}
#ifdef DISABLE_USER_INPUT_MONITOR
// static
std::unique_ptr<UserInputMonitor> UserInputMonitor::Create(
const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) {
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
return nullptr;
}
#endif // DISABLE_USER_INPUT_MONITOR
UserInputMonitor::UserInputMonitor() = default;
UserInputMonitor::~UserInputMonitor() = default;
UserInputMonitor::UserInputMonitor() : key_press_counter_references_(0) {}
UserInputMonitorBase::UserInputMonitorBase() = default;
UserInputMonitor::~UserInputMonitor() {
DCHECK_EQ(0u, key_press_counter_references_);
UserInputMonitorBase::~UserInputMonitorBase() {
DCHECK_EQ(0u, references_);
}
void UserInputMonitor::EnableKeyPressMonitoring() {
void UserInputMonitorBase::EnableKeyPressMonitoring() {
base::AutoLock auto_lock(lock_);
++key_press_counter_references_;
if (key_press_counter_references_ == 1) {
++references_;
if (references_ == 1) {
StartKeyboardMonitoring();
DVLOG(2) << "Started keyboard monitoring.";
}
}
void UserInputMonitor::DisableKeyPressMonitoring() {
void UserInputMonitorBase::DisableKeyPressMonitoring() {
base::AutoLock auto_lock(lock_);
DCHECK_NE(key_press_counter_references_, 0u);
--key_press_counter_references_;
if (key_press_counter_references_ == 0) {
DCHECK_NE(references_, 0u);
--references_;
if (references_ == 0) {
StopKeyboardMonitoring();
DVLOG(2) << "Stopped keyboard monitoring.";
}
......
......@@ -10,6 +10,7 @@
#include <memory>
#include "base/macros.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h"
#include "media/base/media_export.h"
......@@ -20,24 +21,29 @@ class SingleThreadTaskRunner;
namespace media {
// Monitors and notifies about keyboard events.
// Thread safe.
// Utility functions for correctly and atomically reading from/writing to a
// shared memory mapping containing key press count.
uint32_t MEDIA_EXPORT
ReadKeyPressMonitorCount(const base::ReadOnlySharedMemoryMapping& shmem);
void MEDIA_EXPORT
WriteKeyPressMonitorCount(const base::WritableSharedMemoryMapping& shmem,
uint32_t count);
// Base class for audio:: and media:: UserInputMonitor implementations.
class MEDIA_EXPORT UserInputMonitor {
public:
UserInputMonitor();
virtual ~UserInputMonitor();
// Creates a platform-specific instance of UserInputMonitor.
// Creates a platform-specific instance of UserInputMonitorBase.
// |io_task_runner| is the task runner for an IO thread.
// |ui_task_runner| is the task runner for a UI thread.
static std::unique_ptr<UserInputMonitor> Create(
const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner);
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
// A caller must call EnableKeyPressMonitoring and
// DisableKeyPressMonitoring in pair.
void EnableKeyPressMonitoring();
void DisableKeyPressMonitoring();
virtual void EnableKeyPressMonitoring() = 0;
virtual void DisableKeyPressMonitoring() = 0;
// Returns the number of keypresses. The starting point from when it is
// counted is not guaranteed, but consistent within the pair of calls of
......@@ -47,14 +53,34 @@ class MEDIA_EXPORT UserInputMonitor {
// any assumption on the initial value.
virtual uint32_t GetKeyPressCount() const = 0;
private:
DISALLOW_COPY_AND_ASSIGN(UserInputMonitor);
};
// Monitors and notifies about keyboard events.
// Thread safe.
class MEDIA_EXPORT UserInputMonitorBase : public UserInputMonitor {
public:
UserInputMonitorBase();
~UserInputMonitorBase() override;
// A caller must call EnableKeyPressMonitoring and
// DisableKeyPressMonitoring in pair.
void EnableKeyPressMonitoring() override;
void DisableKeyPressMonitoring() override;
private:
virtual void StartKeyboardMonitoring() = 0;
virtual void StopKeyboardMonitoring() = 0;
// Aquired in EnableKeyPressMonitoring()/DisableKeyPressMonitoring(). Together
// with |references_| updated under lock, it is used to ensure operation
// ordering for start/stop keyboard monitoring, i.e. start is always followed
// by stop and start is only called when keyboard monitoring is stopped.
base::Lock lock_;
size_t key_press_counter_references_;
size_t references_ = 0;
DISALLOW_COPY_AND_ASSIGN(UserInputMonitor);
DISALLOW_COPY_AND_ASSIGN(UserInputMonitorBase);
};
} // namespace media
......
......@@ -68,7 +68,7 @@ class UserInputMonitorLinuxCore
DISALLOW_COPY_AND_ASSIGN(UserInputMonitorLinuxCore);
};
class UserInputMonitorLinux : public UserInputMonitor {
class UserInputMonitorLinux : public UserInputMonitorBase {
public:
explicit UserInputMonitorLinux(
const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner);
......@@ -219,6 +219,7 @@ void UserInputMonitorLinuxCore::StopMonitor() {
XCloseDisplay(x_control_display_);
x_control_display_ = NULL;
}
// Stop observing message loop destruction if no event is being monitored.
base::MessageLoopCurrent::Get()->RemoveDestructionObserver(this);
}
......@@ -275,21 +276,21 @@ uint32_t UserInputMonitorLinux::GetKeyPressCount() const {
void UserInputMonitorLinux::StartKeyboardMonitoring() {
io_task_runner_->PostTask(
FROM_HERE,
base::Bind(&UserInputMonitorLinuxCore::StartMonitor, core_->AsWeakPtr()));
FROM_HERE, base::BindOnce(&UserInputMonitorLinuxCore::StartMonitor,
core_->AsWeakPtr()));
}
void UserInputMonitorLinux::StopKeyboardMonitoring() {
io_task_runner_->PostTask(
FROM_HERE,
base::Bind(&UserInputMonitorLinuxCore::StopMonitor, core_->AsWeakPtr()));
FROM_HERE, base::BindOnce(&UserInputMonitorLinuxCore::StopMonitor,
core_->AsWeakPtr()));
}
} // namespace
std::unique_ptr<UserInputMonitor> UserInputMonitor::Create(
const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) {
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
return std::make_unique<UserInputMonitorLinux>(io_task_runner);
}
......
......@@ -13,7 +13,7 @@
namespace media {
namespace {
class UserInputMonitorMac : public UserInputMonitor {
class UserInputMonitorMac : public UserInputMonitorBase {
public:
UserInputMonitorMac();
~UserInputMonitorMac() override;
......@@ -45,8 +45,8 @@ void UserInputMonitorMac::StopKeyboardMonitoring() {}
} // namespace
std::unique_ptr<UserInputMonitor> UserInputMonitor::Create(
const scoped_refptr<base::SingleThreadTaskRunner>& input_task_runner,
const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) {
scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
return std::make_unique<UserInputMonitorMac>();
}
......
......@@ -5,15 +5,11 @@
#include "media/base/user_input_monitor.h"
#include <memory>
#include <utility>
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "build/build_config.h"
#include "media/base/keyboard_event_counter.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkPoint.h"
#if defined(OS_LINUX)
#include "base/files/file_descriptor_watcher_posix.h"
......@@ -29,7 +25,6 @@ TEST(UserInputMonitorTest, CreatePlatformSpecific) {
base::MessageLoopForUI message_loop;
#endif // defined(OS_LINUX)
base::RunLoop run_loop;
std::unique_ptr<UserInputMonitor> monitor = UserInputMonitor::Create(
message_loop.task_runner(), message_loop.task_runner());
......@@ -40,7 +35,20 @@ TEST(UserInputMonitorTest, CreatePlatformSpecific) {
monitor->DisableKeyPressMonitoring();
monitor.reset();
run_loop.RunUntilIdle();
base::RunLoop().RunUntilIdle();
}
TEST(UserInputMonitorTest, KeyPressMonitorReadWriteCount) {
std::unique_ptr<base::MappedReadOnlyRegion> shmem =
std::make_unique<base::MappedReadOnlyRegion>(
base::ReadOnlySharedMemoryRegion::Create(sizeof(uint32_t)));
ASSERT_TRUE(shmem->region.IsValid());
ASSERT_TRUE(shmem->mapping.IsValid());
constexpr uint32_t count = 10;
WriteKeyPressMonitorCount(shmem->mapping, count);
base::ReadOnlySharedMemoryMapping readonly_mapping = shmem->region.Map();
EXPECT_EQ(count, ReadKeyPressMonitorCount(readonly_mapping));
}
} // namespace media
......@@ -79,7 +79,7 @@ class UserInputMonitorWinCore
DISALLOW_COPY_AND_ASSIGN(UserInputMonitorWinCore);
};
class UserInputMonitorWin : public UserInputMonitor {
class UserInputMonitorWin : public UserInputMonitorBase {
public:
explicit UserInputMonitorWin(
const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner);
......@@ -124,8 +124,8 @@ void UserInputMonitorWinCore::StartMonitor() {
std::unique_ptr<base::win::MessageWindow> window =
std::make_unique<base::win::MessageWindow>();
if (!window->Create(base::Bind(&UserInputMonitorWinCore::HandleMessage,
base::Unretained(this)))) {
if (!window->Create(base::BindRepeating(
&UserInputMonitorWinCore::HandleMessage, base::Unretained(this)))) {
PLOG(ERROR) << "Failed to create the raw input window";
return;
}
......@@ -238,21 +238,21 @@ uint32_t UserInputMonitorWin::GetKeyPressCount() const {
void UserInputMonitorWin::StartKeyboardMonitoring() {
ui_task_runner_->PostTask(
FROM_HERE,
base::Bind(&UserInputMonitorWinCore::StartMonitor, core_->AsWeakPtr()));
FROM_HERE, base::BindOnce(&UserInputMonitorWinCore::StartMonitor,
core_->AsWeakPtr()));
}
void UserInputMonitorWin::StopKeyboardMonitoring() {
ui_task_runner_->PostTask(
FROM_HERE,
base::Bind(&UserInputMonitorWinCore::StopMonitor, core_->AsWeakPtr()));
FROM_HERE, base::BindOnce(&UserInputMonitorWinCore::StopMonitor,
core_->AsWeakPtr()));
}
} // namespace
std::unique_ptr<UserInputMonitor> UserInputMonitor::Create(
const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) {
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
return std::make_unique<UserInputMonitorWin>(ui_task_runner);
}
......
......@@ -6,20 +6,34 @@
#include <utility>
#include "media/base/user_input_monitor.h"
namespace media {
MojoAudioInputStreamObserver::MojoAudioInputStreamObserver(
mojom::AudioInputStreamObserverRequest request,
base::OnceClosure recording_started_callback,
base::OnceClosure connection_error_callback)
base::OnceClosure connection_error_callback,
media::UserInputMonitor* user_input_monitor)
: binding_(this, std::move(request)),
recording_started_callback_(std::move(recording_started_callback)) {
recording_started_callback_(std::move(recording_started_callback)),
connection_error_callback_(std::move(connection_error_callback)),
user_input_monitor_(user_input_monitor) {
DCHECK(recording_started_callback_);
binding_.set_connection_error_handler(std::move(connection_error_callback));
if (user_input_monitor_)
user_input_monitor_->EnableKeyPressMonitoring();
// Unretained is safe because |this| owns |binding_|.
binding_.set_connection_error_handler(
base::BindOnce(&MojoAudioInputStreamObserver::OnConnectionError,
base::Unretained(this)));
}
MojoAudioInputStreamObserver::~MojoAudioInputStreamObserver() {
DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
// Check that DisableKeyPressMonitoring() was called.
DCHECK(!user_input_monitor_);
}
void MojoAudioInputStreamObserver::DidStartRecording() {
......@@ -28,4 +42,17 @@ void MojoAudioInputStreamObserver::DidStartRecording() {
std::move(recording_started_callback_).Run();
}
void MojoAudioInputStreamObserver::OnConnectionError() {
DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
if (user_input_monitor_) {
user_input_monitor_->DisableKeyPressMonitoring();
// Set to nullptr to check that DisableKeyPressMonitoring() was called
// before destructor.
user_input_monitor_ = nullptr;
}
std::move(connection_error_callback_).Run();
}
} // namespace media
......@@ -11,19 +11,26 @@
namespace media {
class UserInputMonitor;
class MEDIA_MOJO_EXPORT MojoAudioInputStreamObserver
: public mojom::AudioInputStreamObserver {
public:
MojoAudioInputStreamObserver(mojom::AudioInputStreamObserverRequest request,
base::OnceClosure recording_started_callback,
base::OnceClosure connection_error_callback);
base::OnceClosure connection_error_callback,
media::UserInputMonitor* user_input_monitor);
~MojoAudioInputStreamObserver() override;
void DidStartRecording() override;
private:
void OnConnectionError();
mojo::Binding<AudioInputStreamObserver> binding_;
base::OnceClosure recording_started_callback_;
base::OnceClosure connection_error_callback_;
media::UserInputMonitor* user_input_monitor_;
SEQUENCE_CHECKER(owning_sequence_);
......
......@@ -29,7 +29,8 @@ class MojoAudioInputStreamObserverTest : public testing::Test {
base::Unretained(this)),
base::BindOnce(
&MojoAudioInputStreamObserverTest::BindingConnectionError,
base::Unretained(this)));
base::Unretained(this)),
nullptr /*user_input_monitor*/);
}
MOCK_METHOD0(RecordingStartedCallback, void());
......
......@@ -57,6 +57,8 @@ source_set("lib") {
"sync_reader.h",
"system_info.cc",
"system_info.h",
"user_input_monitor.cc",
"user_input_monitor.h",
]
public_deps = [
......@@ -90,6 +92,7 @@ source_set("tests") {
"test/service_lifetime_test_template.h",
"test/service_observer_mock.cc",
"test/service_observer_mock.h",
"user_input_monitor_unittest.cc",
]
deps = [
......
......@@ -14,6 +14,7 @@
#include "mojo/public/cpp/system/buffer.h"
#include "mojo/public/cpp/system/handle.h"
#include "mojo/public/cpp/system/platform_handle.h"
#include "services/audio/user_input_monitor.h"
namespace audio {
......@@ -28,7 +29,7 @@ InputStream::InputStream(CreatedCallback created_callback,
media::mojom::AudioInputStreamObserverPtr observer,
media::mojom::AudioLogPtr log,
media::AudioManager* audio_manager,
media::UserInputMonitor* user_input_monitor,
std::unique_ptr<UserInputMonitor> user_input_monitor,
const std::string& device_id,
const media::AudioParameters& params,
uint32_t shared_memory_count,
......@@ -46,6 +47,7 @@ InputStream::InputStream(CreatedCallback created_callback,
shared_memory_count,
params,
&foreign_socket_)),
user_input_monitor_(std::move(user_input_monitor)),
weak_factory_(this) {
DCHECK(audio_manager);
DCHECK(binding_.is_bound());
......@@ -75,8 +77,8 @@ InputStream::InputStream(CreatedCallback created_callback,
}
controller_ = media::AudioInputController::Create(
audio_manager, this, writer_.get(), user_input_monitor, params, device_id,
enable_agc);
audio_manager, this, writer_.get(), user_input_monitor_.get(), params,
device_id, enable_agc);
}
InputStream::~InputStream() {
......
......@@ -21,12 +21,13 @@ namespace media {
class AudioInputSyncWriter;
class AudioManager;
class AudioParameters;
class UserInputMonitor;
} // namespace media
namespace audio {
class UserInputMonitor;
class InputStream final : public media::mojom::AudioInputStream,
public media::AudioInputController::EventHandler {
public:
......@@ -41,7 +42,7 @@ class InputStream final : public media::mojom::AudioInputStream,
media::mojom::AudioInputStreamObserverPtr observer,
media::mojom::AudioLogPtr log,
media::AudioManager* manager,
media::UserInputMonitor* user_input_monitor,
std::unique_ptr<UserInputMonitor> user_input_monitor,
const std::string& device_id,
const media::AudioParameters& params,
uint32_t shared_memory_count,
......@@ -76,6 +77,7 @@ class InputStream final : public media::mojom::AudioInputStream,
base::CancelableSyncSocket foreign_socket_;
const std::unique_ptr<media::AudioInputSyncWriter> writer_;
scoped_refptr<media::AudioInputController> controller_;
const std::unique_ptr<UserInputMonitor> user_input_monitor_;
SEQUENCE_CHECKER(owning_sequence_);
......
......@@ -137,7 +137,7 @@ class AudioServiceInputStreamTest : public testing::Test {
mojo::MakeRequest(&stream_ptr), client_.MakePtr(), observer_.MakePtr(),
log_.MakePtr(), kDefaultDeviceId,
media::AudioParameters::UnavailableDeviceParams(),
kDefaultSharedMemoryCount, enable_agc,
kDefaultSharedMemoryCount, enable_agc, mojo::ScopedSharedBufferHandle(),
base::BindOnce(&AudioServiceInputStreamTest::OnCreated,
base::Unretained(this)));
return stream_ptr;
......
......@@ -33,14 +33,18 @@ interface StreamFactory {
// obtained from the audio.mojom.SystemInfo interface, or "default".
// |shared_memory_count| indicates how many buffer segments can the input
// stream client read at once, to avoid data overwriting. |enable_agc| is used
// for enabling automatic gain control.
// for enabling automatic gain control. |key_press_count_buffer| is an
// optional readonly shared memory handle for reading the current key press
// count, updated by browser process in media::UserInputMonitor
// implementation.
CreateInputStream(
media.mojom.AudioInputStream& stream,
media.mojom.AudioInputStreamClient client,
media.mojom.AudioInputStreamObserver observer,
media.mojom.AudioLog log,
string device_id, media.mojom.AudioParameters params,
uint32 shared_memory_count, bool enable_agc)
uint32 shared_memory_count, bool enable_agc,
handle<shared_buffer>? key_press_count_buffer)
=> (media.mojom.AudioDataPipe? data_pipe, bool initially_muted);
// Creates an AudioOutputStream and returns the AudioDataPipe it reads data
......
......@@ -7,16 +7,16 @@
#include <utility>
#include "base/unguessable_token.h"
#include "media/base/user_input_monitor.h"
#include "services/audio/input_stream.h"
#include "services/audio/local_muter.h"
#include "services/audio/output_stream.h"
#include "services/audio/user_input_monitor.h"
#include "services/service_manager/public/cpp/service_context_ref.h"
namespace audio {
StreamFactory::StreamFactory(media::AudioManager* audio_manager)
: audio_manager_(audio_manager), user_input_monitor_(nullptr) {}
: audio_manager_(audio_manager) {}
StreamFactory::~StreamFactory() {
DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
......@@ -38,6 +38,7 @@ void StreamFactory::CreateInputStream(
const media::AudioParameters& params,
uint32_t shared_memory_count,
bool enable_agc,
mojo::ScopedSharedBufferHandle key_press_count_buffer,
CreateInputStreamCallback created_callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
......@@ -48,8 +49,9 @@ void StreamFactory::CreateInputStream(
input_streams_.insert(std::make_unique<InputStream>(
std::move(created_callback), std::move(deleter_callback),
std::move(stream_request), std::move(client), std::move(observer),
std::move(log), audio_manager_, user_input_monitor_, device_id, params,
shared_memory_count, enable_agc));
std::move(log), audio_manager_,
UserInputMonitor::Create(std::move(key_press_count_buffer)), device_id,
params, shared_memory_count, enable_agc));
}
void StreamFactory::CreateOutputStream(
......
......@@ -27,7 +27,6 @@ class UnguessableToken;
namespace media {
class AudioManager;
class AudioParameters;
class UserInputMonitor;
} // namespace media
namespace service_manager {
......@@ -61,6 +60,7 @@ class StreamFactory final : public mojom::StreamFactory {
const media::AudioParameters& params,
uint32_t shared_memory_count,
bool enable_agc,
mojo::ScopedSharedBufferHandle key_press_count_buffer,
CreateInputStreamCallback created_callback) final;
void CreateOutputStream(
......@@ -87,7 +87,6 @@ class StreamFactory final : public mojom::StreamFactory {
SEQUENCE_CHECKER(owning_sequence_);
media::AudioManager* const audio_manager_;
media::UserInputMonitor* user_input_monitor_;
mojo::BindingSet<mojom::StreamFactory,
std::unique_ptr<service_manager::ServiceContextRef>>
......
// 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/user_input_monitor.h"
#include <utility>
#include "mojo/public/cpp/system/platform_handle.h"
namespace audio {
// static
std::unique_ptr<UserInputMonitor> UserInputMonitor::Create(
mojo::ScopedSharedBufferHandle handle) {
base::ReadOnlySharedMemoryRegion memory =
mojo::UnwrapReadOnlySharedMemoryRegion(std::move(handle));
if (memory.IsValid())
return std::make_unique<UserInputMonitor>(memory.Map());
return nullptr;
}
UserInputMonitor::UserInputMonitor(
base::ReadOnlySharedMemoryMapping memory_mapping)
: key_press_count_mapping_(std::move(memory_mapping)) {}
UserInputMonitor::~UserInputMonitor() = default;
void UserInputMonitor::EnableKeyPressMonitoring() {}
void UserInputMonitor::DisableKeyPressMonitoring() {}
uint32_t UserInputMonitor::GetKeyPressCount() const {
return media::ReadKeyPressMonitorCount(key_press_count_mapping_);
}
} // 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_USER_INPUT_MONITOR_H_
#define SERVICES_AUDIO_USER_INPUT_MONITOR_H_
#include <memory>
#include "base/memory/shared_memory_mapping.h"
#include "media/base/user_input_monitor.h"
#include "mojo/public/cpp/system/buffer.h"
namespace audio {
// TODO(https://crbug.com/836226) remove inheritance after switching to audio
// service input streams.
class UserInputMonitor : public media::UserInputMonitor {
public:
explicit UserInputMonitor(base::ReadOnlySharedMemoryMapping memory_mapping);
~UserInputMonitor() override;
// Returns nullptr for invalid handle.
static std::unique_ptr<UserInputMonitor> Create(
mojo::ScopedSharedBufferHandle keypress_count_buffer);
void EnableKeyPressMonitoring() override;
void DisableKeyPressMonitoring() override;
uint32_t GetKeyPressCount() const override;
private:
base::ReadOnlySharedMemoryMapping key_press_count_mapping_;
DISALLOW_COPY_AND_ASSIGN(UserInputMonitor);
};
} // namespace audio
#endif // SERVICES_AUDIO_USER_INPUT_MONITOR_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/user_input_monitor.h"
#include <memory>
#include <utility>
#include "media/base/user_input_monitor.h"
#include "mojo/public/cpp/system/platform_handle.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace audio {
namespace {
constexpr uint32_t kKeyPressCount = 10;
}
TEST(AudioServiceUserInputMonitorTest, CreateWithValidHandle) {
std::unique_ptr<base::MappedReadOnlyRegion> shmem =
std::make_unique<base::MappedReadOnlyRegion>(
base::ReadOnlySharedMemoryRegion::Create(sizeof(uint32_t)));
ASSERT_TRUE(shmem->region.IsValid());
ASSERT_TRUE(shmem->mapping.IsValid());
mojo::ScopedSharedBufferHandle handle =
mojo::WrapReadOnlySharedMemoryRegion(shmem->region.Duplicate());
EXPECT_TRUE(UserInputMonitor::Create(std::move(handle)));
}
TEST(AudioServiceUserInputMonitorTest, CreateWithInvalidHandle_ReturnsNullptr) {
EXPECT_EQ(nullptr,
UserInputMonitor::Create(mojo::ScopedSharedBufferHandle()));
}
TEST(AudioServiceUserInputMonitorTest, GetKeyPressCount) {
std::unique_ptr<base::MappedReadOnlyRegion> shmem =
std::make_unique<base::MappedReadOnlyRegion>(
base::ReadOnlySharedMemoryRegion::Create(sizeof(uint32_t)));
ASSERT_TRUE(shmem->region.IsValid());
ASSERT_TRUE(shmem->mapping.IsValid());
mojo::ScopedSharedBufferHandle handle =
mojo::WrapReadOnlySharedMemoryRegion(shmem->region.Duplicate());
std::unique_ptr<UserInputMonitor> monitor =
UserInputMonitor::Create(std::move(handle));
EXPECT_TRUE(monitor);
media::WriteKeyPressMonitorCount(shmem->mapping, kKeyPressCount);
EXPECT_EQ(kKeyPressCount, monitor->GetKeyPressCount());
}
TEST(AudioServiceUserInputMonitorTest, GetKeyPressCountAfterMemoryUnmap) {
std::unique_ptr<base::MappedReadOnlyRegion> shmem =
std::make_unique<base::MappedReadOnlyRegion>(
base::ReadOnlySharedMemoryRegion::Create(sizeof(uint32_t)));
ASSERT_TRUE(shmem->region.IsValid());
ASSERT_TRUE(shmem->mapping.IsValid());
mojo::ScopedSharedBufferHandle handle =
mojo::WrapReadOnlySharedMemoryRegion(shmem->region.Duplicate());
std::unique_ptr<UserInputMonitor> monitor =
UserInputMonitor::Create(std::move(handle));
EXPECT_TRUE(monitor);
media::WriteKeyPressMonitorCount(shmem->mapping, kKeyPressCount);
EXPECT_EQ(kKeyPressCount, monitor->GetKeyPressCount());
// ReadOnlyMapping should still be valid, containing the last updated value,
// after shmem reset.
shmem.reset();
EXPECT_EQ(kKeyPressCount, monitor->GetKeyPressCount());
}
} // 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