Commit 73a21d4b authored by Guido Urdaneta's avatar Guido Urdaneta Committed by Commit Bot

Add LogFactoryManager to audio service.

This allows the browser process to set a factory so that the audio
service can create audio logs on the browser process.

Bug: 812557
Change-Id: Ia88acb6cb911fc0ad4a47f20b3a628c814233c6b
Reviewed-on: https://chromium-review.googlesource.com/1128974Reviewed-by: default avatarTom Sepez <tsepez@chromium.org>
Reviewed-by: default avatarMax Morin <maxmorin@chromium.org>
Reviewed-by: default avatarMarina Ciocea <marinaciocea@chromium.org>
Commit-Queue: Guido Urdaneta <guidou@chromium.org>
Cr-Commit-Position: refs/heads/master@{#575561}
parent 54d95ca9
......@@ -6,12 +6,16 @@
#include <utility>
#include "base/feature_list.h"
#include "base/metrics/histogram_macros.h"
#include "base/time/default_tick_clock.h"
#include "content/browser/media/audio_log_factory.h"
#include "content/public/browser/child_process_data.h"
#include "content/public/browser/child_process_termination_info.h"
#include "content/public/common/content_features.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/audio/public/mojom/constants.mojom.h"
#include "services/audio/public/mojom/log_factory_manager.mojom.h"
namespace content {
......@@ -88,13 +92,14 @@ void AudioServiceListener::Metrics::LogServiceStartStatus(
AudioServiceListener::AudioServiceListener(
std::unique_ptr<service_manager::Connector> connector)
: binding_(this),
connector_(std::move(connector)),
metrics_(base::DefaultTickClock::GetInstance()) {
DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
if (!connector)
if (!connector_)
return; // Happens in unittests.
service_manager::mojom::ServiceManagerPtr service_manager;
connector->BindInterface(service_manager::mojom::kServiceName,
connector_->BindInterface(service_manager::mojom::kServiceName,
&service_manager);
service_manager::mojom::ServiceManagerListenerPtr listener;
service_manager::mojom::ServiceManagerListenerRequest request(
......@@ -123,6 +128,7 @@ void AudioServiceListener::OnInit(
if (instance->identity.name() == audio::mojom::kServiceName) {
process_id_ = instance->pid;
metrics_.ServiceAlreadyRunning();
MaybeSetLogFactory();
break;
}
}
......@@ -134,6 +140,7 @@ void AudioServiceListener::OnServiceCreated(
if (service->identity.name() != audio::mojom::kServiceName)
return;
metrics_.ServiceCreated();
MaybeSetLogFactory();
}
void AudioServiceListener::OnServiceStarted(
......@@ -169,6 +176,7 @@ void AudioServiceListener::OnServiceStopped(
if (identity.name() != audio::mojom::kServiceName)
return;
metrics_.ServiceStopped();
log_factory_is_set_ = false;
}
void AudioServiceListener::BrowserChildProcessHostDisconnected(
......@@ -203,4 +211,20 @@ void AudioServiceListener::BrowserChildProcessKilled(
Metrics::ServiceProcessTerminationStatus::kKill);
}
void AudioServiceListener::MaybeSetLogFactory() {
DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
if (!base::FeatureList::IsEnabled(features::kAudioServiceOutOfProcess) ||
!connector_ || log_factory_is_set_)
return;
media::mojom::AudioLogFactoryPtr audio_log_factory_ptr;
mojo::MakeStrongBinding(std::make_unique<AudioLogFactory>(),
mojo::MakeRequest(&audio_log_factory_ptr));
audio::mojom::LogFactoryManagerPtr log_factory_manager_ptr;
connector_->BindInterface(audio::mojom::kServiceName,
mojo::MakeRequest(&log_factory_manager_ptr));
log_factory_manager_ptr->SetLogFactory(std::move(audio_log_factory_ptr));
log_factory_is_set_ = true;
}
} // namespace content
......@@ -116,9 +116,13 @@ class CONTENT_EXPORT AudioServiceListener
void BrowserChildProcessKilled(const ChildProcessData& data,
const ChildProcessTerminationInfo& info) final;
void MaybeSetLogFactory();
mojo::Binding<service_manager::mojom::ServiceManagerListener> binding_;
std::unique_ptr<service_manager::Connector> connector_;
base::ProcessId process_id_ = base::kNullProcessId;
Metrics metrics_;
bool log_factory_is_set_ = false;
SEQUENCE_CHECKER(owning_sequence_);
DISALLOW_COPY_AND_ASSIGN(AudioServiceListener);
......
......@@ -81,6 +81,7 @@
"info",
"debug_recording",
"device_notifier",
"log_factory_manager",
"stream_factory",
"testing_api"
],
......
......@@ -51,6 +51,12 @@ source_set("lib") {
"input_sync_writer.h",
"local_muter.cc",
"local_muter.h",
"log_adapter.cc",
"log_adapter.h",
"log_factory_adapter.cc",
"log_factory_adapter.h",
"log_factory_manager.cc",
"log_factory_manager.h",
"loopback_stream.cc",
"loopback_stream.h",
"output_controller.cc",
......@@ -104,6 +110,7 @@ source_set("tests") {
"input_stream_unittest.cc",
"input_sync_writer_unittest.cc",
"local_muter_unittest.cc",
"log_factory_manager_unittest.cc",
"loopback_stream_unittest.cc",
"output_controller_unittest.cc",
"output_stream_unittest.cc",
......
......@@ -27,4 +27,9 @@ media::AudioManager* InProcessAudioManagerAccessor::GetAudioManager() {
return audio_manager_;
}
void InProcessAudioManagerAccessor::SetAudioLogFactory(
media::AudioLogFactory* factory) {
NOTREACHED();
}
} // namespace audio
......@@ -10,6 +10,7 @@
namespace media {
class AudioManager;
class AudioLogFactory;
}
namespace audio {
......@@ -25,6 +26,9 @@ class InProcessAudioManagerAccessor : public Service::AudioManagerAccessor {
void Shutdown() final {} // AudioManager must be shut down by its owner.
media::AudioManager* GetAudioManager() final;
// Should not be called on this implementation.
void SetAudioLogFactory(media::AudioLogFactory* factory) final;
private:
media::AudioManager* const audio_manager_;
DISALLOW_COPY_AND_ASSIGN(InProcessAudioManagerAccessor);
......
// 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/log_adapter.h"
#include <utility>
namespace audio {
LogAdapter::LogAdapter(media::mojom::AudioLogPtr audio_log)
: audio_log_(std::move(audio_log)) {}
LogAdapter::~LogAdapter() = default;
void LogAdapter::OnCreated(const media::AudioParameters& params,
const std::string& device_id) {
audio_log_->OnCreated(params, device_id);
}
void LogAdapter::OnStarted() {
audio_log_->OnStarted();
}
void LogAdapter::OnStopped() {
audio_log_->OnStopped();
}
void LogAdapter::OnClosed() {
audio_log_->OnClosed();
}
void LogAdapter::OnError() {
audio_log_->OnError();
}
void LogAdapter::OnSetVolume(double volume) {
audio_log_->OnSetVolume(volume);
}
void LogAdapter::OnLogMessage(const std::string& message) {
audio_log_->OnLogMessage(message);
}
} // 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_LOG_ADAPTER_H_
#define SERVICES_AUDIO_LOG_ADAPTER_H_
#include <string>
#include "media/audio/audio_logging.h"
#include "media/mojo/interfaces/audio_logging.mojom.h"
namespace media {
class AudioParameters;
}
namespace audio {
// This class wraps a media::mojom::AudioLogPtr into a media::AudioLog.
class LogAdapter : public media::AudioLog {
public:
explicit LogAdapter(media::mojom::AudioLogPtr audio_log);
~LogAdapter() override;
// media::AudioLog implementation.
void OnCreated(const media::AudioParameters& params,
const std::string& device_id) override;
void OnStarted() override;
void OnStopped() override;
void OnClosed() override;
void OnError() override;
void OnSetVolume(double volume) override;
void OnLogMessage(const std::string& message) override;
private:
media::mojom::AudioLogPtr audio_log_;
DISALLOW_COPY_AND_ASSIGN(LogAdapter);
};
} // namespace audio
#endif // SERVICES_AUDIO_LOG_ADAPTER_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/log_factory_adapter.h"
#include <utility>
#include "services/audio/log_adapter.h"
namespace audio {
const int kMaxPendingLogRequests = 500;
struct LogFactoryAdapter::PendingLogRequest {
PendingLogRequest(media::mojom::AudioLogComponent component,
int component_id,
media::mojom::AudioLogRequest request)
: component(component),
component_id(component_id),
request(std::move(request)) {}
PendingLogRequest(PendingLogRequest&& other) = default;
PendingLogRequest& operator=(PendingLogRequest&& other) = default;
PendingLogRequest(const PendingLogRequest& other) = delete;
PendingLogRequest& operator=(const PendingLogRequest& other) = delete;
~PendingLogRequest() = default;
media::mojom::AudioLogComponent component;
int component_id;
media::mojom::AudioLogRequest request;
};
LogFactoryAdapter::LogFactoryAdapter() = default;
LogFactoryAdapter::~LogFactoryAdapter() = default;
void LogFactoryAdapter::SetLogFactory(
media::mojom::AudioLogFactoryPtr log_factory) {
if (log_factory_) {
LOG(WARNING) << "Attempting to set log factory more than once. Ignoring "
"request.";
return;
}
log_factory_ = std::move(log_factory);
while (!pending_requests_.empty()) {
auto& front = pending_requests_.front();
log_factory_->CreateAudioLog(front.component, front.component_id,
std::move(front.request));
pending_requests_.pop();
}
}
std::unique_ptr<media::AudioLog> LogFactoryAdapter::CreateAudioLog(
AudioComponent component,
int component_id) {
media::mojom::AudioLogPtr audio_log_ptr;
media::mojom::AudioLogRequest audio_log_request =
mojo::MakeRequest(&audio_log_ptr);
media::mojom::AudioLogComponent mojo_component =
static_cast<media::mojom::AudioLogComponent>(component);
if (log_factory_) {
log_factory_->CreateAudioLog(mojo_component, component_id,
std::move(audio_log_request));
} else if (pending_requests_.size() >= kMaxPendingLogRequests) {
LOG(WARNING) << "Maximum number of queued log requests exceeded. Fulfilling"
" request with fake log.";
return fake_log_factory_.CreateAudioLog(component, component_id);
} else {
pending_requests_.emplace(mojo_component, component_id,
std::move(audio_log_request));
}
return std::make_unique<LogAdapter>(std::move(audio_log_ptr));
}
} // 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_LOG_FACTORY_ADAPTER_H_
#define SERVICES_AUDIO_LOG_FACTORY_ADAPTER_H_
#include <memory>
#include "base/containers/queue.h"
#include "media/audio/audio_logging.h"
#include "media/audio/fake_audio_log_factory.h"
#include "services/audio/public/mojom/log_factory_manager.mojom.h"
namespace media {
class AudioLogFactory;
} // namespace media
namespace audio {
// This class allows setting a mojo audio log factory to create audio logs
// in the audio service. It also acts as a media::AudioLogFactory to interface
// with AudioManager.
class LogFactoryAdapter final : public media::AudioLogFactory {
public:
LogFactoryAdapter();
~LogFactoryAdapter() final;
void SetLogFactory(media::mojom::AudioLogFactoryPtr log_factory);
// media::AudioLogFactory implementation
std::unique_ptr<media::AudioLog> CreateAudioLog(AudioComponent component,
int component_id) override;
private:
struct PendingLogRequest;
media::mojom::AudioLogFactoryPtr log_factory_;
base::queue<PendingLogRequest> pending_requests_;
media::FakeAudioLogFactory fake_log_factory_;
DISALLOW_COPY_AND_ASSIGN(LogFactoryAdapter);
};
} // namespace audio
#endif // SERVICES_AUDIO_LOG_FACTORY_ADAPTER_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/log_factory_manager.h"
#include <utility>
#include "services/service_manager/public/cpp/service_context_ref.h"
namespace audio {
LogFactoryManager::LogFactoryManager() {}
LogFactoryManager::~LogFactoryManager() {
DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
}
void LogFactoryManager::Bind(mojom::LogFactoryManagerRequest request,
TracedServiceRef context_ref) {
DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
bindings_.AddBinding(this, std::move(request), std::move(context_ref));
}
void LogFactoryManager::SetLogFactory(
media::mojom::AudioLogFactoryPtr log_factory) {
DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
log_factory_adapter_.SetLogFactory(std::move(log_factory));
}
media::AudioLogFactory* LogFactoryManager::GetLogFactory() {
DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
return &log_factory_adapter_;
}
} // 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_LOG_FACTORY_MANAGER_H_
#define SERVICES_AUDIO_LOG_FACTORY_MANAGER_H_
#include <memory>
#include "mojo/public/cpp/bindings/binding_set.h"
#include "services/audio/log_factory_adapter.h"
#include "services/audio/public/mojom/log_factory_manager.mojom.h"
#include "services/audio/traced_service_ref.h"
namespace media {
class AudioLogFactory;
}
namespace audio {
// This class is used to provide the LogFactoryManager interface. It will
// typically be instantiated when needed and remain for the lifetime of the
// service.
class LogFactoryManager final : public mojom::LogFactoryManager {
public:
LogFactoryManager();
~LogFactoryManager() final;
void Bind(mojom::LogFactoryManagerRequest request,
TracedServiceRef context_ref);
// LogFactoryManager implementation.
void SetLogFactory(media::mojom::AudioLogFactoryPtr log_factory) final;
media::AudioLogFactory* GetLogFactory();
private:
mojo::BindingSet<mojom::LogFactoryManager, TracedServiceRef> bindings_;
LogFactoryAdapter log_factory_adapter_;
SEQUENCE_CHECKER(owning_sequence_);
DISALLOW_COPY_AND_ASSIGN(LogFactoryManager);
};
} // namespace audio
#endif // SERVICES_AUDIO_LOG_FACTORY_MANAGER_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/log_factory_manager.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/memory/ptr_util.h"
#include "base/test/scoped_task_environment.h"
#include "media/mojo/interfaces/audio_logging.mojom.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/audio/traced_service_ref.h"
#include "services/service_manager/public/cpp/service_context_ref.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace audio {
using testing::_;
using testing::SaveArg;
namespace {
class MockAudioLog : public media::mojom::AudioLog {
public:
MockAudioLog() {}
MOCK_METHOD2(OnCreated,
void(const media::AudioParameters& params,
const std::string& device_id));
MOCK_METHOD0(OnStarted, void());
MOCK_METHOD0(OnStopped, void());
MOCK_METHOD0(OnClosed, void());
MOCK_METHOD0(OnError, void());
MOCK_METHOD1(OnSetVolume, void(double));
MOCK_METHOD1(OnLogMessage, void(const std::string&));
};
class MockAudioLogFactory : public media::mojom::AudioLogFactory {
public:
MockAudioLogFactory(media::mojom::AudioLogFactoryRequest request,
size_t num_mock_logs)
: binding_(this, std::move(request)) {
for (size_t i = 0; i < num_mock_logs; ++i)
mock_logs_.push_back(new MockAudioLog());
}
MOCK_METHOD2(MockCreateAudioLog,
void(media::mojom::AudioLogComponent, int32_t));
void CreateAudioLog(
media::mojom::AudioLogComponent component,
int32_t component_id,
media::mojom::AudioLogRequest audio_log_request) override {
MockCreateAudioLog(component, component_id);
mojo::MakeStrongBinding(base::WrapUnique(mock_logs_[current_mock_log_++]),
std::move(audio_log_request));
};
MockAudioLog* GetMockLog(size_t index) { return mock_logs_[index]; }
private:
mojo::Binding<media::mojom::AudioLogFactory> binding_;
size_t current_mock_log_ = 0;
std::vector<MockAudioLog*> mock_logs_;
DISALLOW_COPY_AND_ASSIGN(MockAudioLogFactory);
};
} // namespace
class LogFactoryManagerTest : public ::testing::Test {
public:
LogFactoryManagerTest()
: service_ref_factory_(
base::BindRepeating(&LogFactoryManagerTest::OnNoServiceRefs,
base::Unretained(this))) {}
protected:
MOCK_METHOD0(OnNoServiceRefs, void());
void CreateLogFactoryManager() {
log_factory_manager_ = std::make_unique<LogFactoryManager>();
log_factory_manager_->Bind(
mojo::MakeRequest(&log_factory_manager_ptr_),
TracedServiceRef(service_ref_factory_.CreateRef(),
"audio::LogFactoryManager Binding"));
EXPECT_FALSE(service_ref_factory_.HasNoRefs());
}
void DestroyLogFactoryManager() {
log_factory_manager_ptr_.reset();
scoped_task_environment_.RunUntilIdle();
EXPECT_TRUE(service_ref_factory_.HasNoRefs());
}
base::test::ScopedTaskEnvironment scoped_task_environment_;
mojom::LogFactoryManagerPtr log_factory_manager_ptr_;
std::unique_ptr<LogFactoryManager> log_factory_manager_;
private:
service_manager::ServiceContextRefFactory service_ref_factory_;
DISALLOW_COPY_AND_ASSIGN(LogFactoryManagerTest);
};
TEST_F(LogFactoryManagerTest, LogFactoryManagerQueuesRequestsAndSetsFactory) {
EXPECT_CALL(*this, OnNoServiceRefs());
CreateLogFactoryManager();
// Create a log before setting the log factory.
const int kComponentId1 = 1;
const double kVolume1 = 0.5;
media::AudioLogFactory* log_factory = log_factory_manager_->GetLogFactory();
std::unique_ptr<media::AudioLog> log1 = log_factory->CreateAudioLog(
media::AudioLogFactory::AUDIO_OUTPUT_STREAM, kComponentId1);
log1->OnStarted();
log1->OnSetVolume(kVolume1);
log1->OnStopped();
log1->OnClosed();
// Set the factory.
media::mojom::AudioLogFactoryPtr log_factory_ptr;
MockAudioLogFactory mock_factory(mojo::MakeRequest(&log_factory_ptr), 2);
MockAudioLog* mock_log1 = mock_factory.GetMockLog(0);
testing::InSequence s;
// Set the factory and expect that queued operations run.
EXPECT_CALL(mock_factory,
MockCreateAudioLog(media::mojom::AudioLogComponent::kOutputStream,
kComponentId1));
EXPECT_CALL(*mock_log1, OnStarted());
EXPECT_CALL(*mock_log1, OnSetVolume(kVolume1));
EXPECT_CALL(*mock_log1, OnStopped());
EXPECT_CALL(*mock_log1, OnClosed());
log_factory_manager_ptr_->SetLogFactory(std::move(log_factory_ptr));
scoped_task_environment_.RunUntilIdle();
// Create another log after the factory is already set.
const int kComponentId2 = 2;
const double kVolume2 = 0.1;
EXPECT_CALL(
mock_factory,
MockCreateAudioLog(media::mojom::AudioLogComponent::kInputController,
kComponentId2));
MockAudioLog* mock_log2 = mock_factory.GetMockLog(1);
EXPECT_CALL(*mock_log2, OnStarted());
EXPECT_CALL(*mock_log2, OnSetVolume(kVolume2));
EXPECT_CALL(*mock_log2, OnStopped());
EXPECT_CALL(*mock_log2, OnClosed());
std::unique_ptr<media::AudioLog> log2 = log_factory->CreateAudioLog(
media::AudioLogFactory::AUDIO_INPUT_CONTROLLER, 2);
log2->OnStarted();
log2->OnSetVolume(kVolume2);
log2->OnStopped();
log2->OnClosed();
// Ensure all mock objects are released.
log1.reset();
log2.reset();
DestroyLogFactoryManager();
}
} // namespace audio
......@@ -9,6 +9,7 @@
"debug_recording": [ "audio.mojom.DebugRecording" ],
"stream_factory": [ "audio.mojom.StreamFactory" ],
"device_notifier": [ "audio.mojom.DeviceNotifier" ],
"log_factory_manager": [ "audio.mojom.LogFactoryManager" ],
"testing_api": [ "audio.mojom.TestingApi" ]
},
"requires": {
......
......@@ -90,12 +90,10 @@ media::AudioManager* OwningAudioManagerAccessor::GetAudioManager() {
if (!audio_manager_) {
TRACE_EVENT0("audio", "AudioManager creation");
DCHECK(audio_manager_factory_cb_);
DCHECK(log_factory_);
base::TimeTicks creation_start_time = base::TimeTicks::Now();
// TODO(http://crbug/812557): pass AudioLogFactory (needed for output
// streams).
audio_manager_ = std::move(audio_manager_factory_cb_)
.Run(std::make_unique<MainThread>(), &log_factory_);
.Run(std::make_unique<MainThread>(), log_factory_);
DCHECK(audio_manager_);
UMA_HISTOGRAM_TIMES("Media.AudioService.AudioManagerStartupTime",
base::TimeTicks::Now() - creation_start_time);
......@@ -104,6 +102,11 @@ media::AudioManager* OwningAudioManagerAccessor::GetAudioManager() {
return audio_manager_.get();
}
void OwningAudioManagerAccessor::SetAudioLogFactory(
media::AudioLogFactory* log_factory) {
log_factory_ = log_factory;
}
void OwningAudioManagerAccessor::Shutdown() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (audio_manager_)
......
......@@ -10,7 +10,6 @@
#include "base/macros.h"
#include "base/threading/thread_checker.h"
#include "build/build_config.h"
#include "media/audio/fake_audio_log_factory.h"
#include "services/audio/service.h"
#if defined(OS_WIN)
......@@ -40,6 +39,7 @@ class OwningAudioManagerAccessor : public Service::AudioManagerAccessor {
~OwningAudioManagerAccessor() override;
media::AudioManager* GetAudioManager() final;
void SetAudioLogFactory(media::AudioLogFactory* factory) final;
void Shutdown() final;
private:
......@@ -49,10 +49,7 @@ class OwningAudioManagerAccessor : public Service::AudioManagerAccessor {
#endif
AudioManagerFactoryCallback audio_manager_factory_cb_;
std::unique_ptr<media::AudioManager> audio_manager_;
// TODO(http://crbug/812557): Use a real AudioLogFactory (needed for output
// streams).
media::FakeAudioLogFactory log_factory_;
media::AudioLogFactory* log_factory_ = nullptr; // not owned.
THREAD_CHECKER(thread_checker_);
DISALLOW_COPY_AND_ASSIGN(OwningAudioManagerAccessor);
......
......@@ -9,6 +9,7 @@ mojom("mojom") {
"audio_device_description.mojom",
"debug_recording.mojom",
"device_notifications.mojom",
"log_factory_manager.mojom",
"stream_factory.mojom",
"system_info.mojom",
"testing_api.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 "media/mojo/interfaces/audio_logging.mojom";
// This interface is exposed by the audio service to allow trusted clients
// (like the browser process) to set a factory for creating audio logs.
interface LogFactoryManager {
// Sets the factory for creating audio logs. If a previous factory exists,
// the request is ignored.
SetLogFactory(media.mojom.AudioLogFactory factory);
};
......@@ -15,6 +15,7 @@
#include "media/audio/audio_manager.h"
#include "services/audio/debug_recording.h"
#include "services/audio/device_notifier.h"
#include "services/audio/log_factory_manager.h"
#include "services/audio/service_metrics.h"
#include "services/audio/system_info.h"
#include "services/service_manager/public/cpp/service_context.h"
......@@ -28,15 +29,22 @@ namespace audio {
Service::Service(std::unique_ptr<AudioManagerAccessor> audio_manager_accessor,
base::TimeDelta quit_timeout,
bool device_notifier_enabled,
bool enable_remote_client_support,
std::unique_ptr<service_manager::BinderRegistry> registry)
: quit_timeout_(quit_timeout),
audio_manager_accessor_(std::move(audio_manager_accessor)),
device_notifier_enabled_(device_notifier_enabled),
enable_remote_client_support_(enable_remote_client_support),
registry_(std::move(registry)) {
DCHECK(audio_manager_accessor_);
if (!device_notifier_enabled)
if (enable_remote_client_support_) {
log_factory_manager_ = std::make_unique<LogFactoryManager>();
audio_manager_accessor_->SetAudioLogFactory(
log_factory_manager_->GetLogFactory());
} else {
// Start device monitoring explicitly if no mojo device notifier will be
// created. This is required for in-process device notifications.
InitializeDeviceMonitor();
}
}
Service::~Service() {
......@@ -77,9 +85,11 @@ void Service::OnStart() {
&Service::BindDebugRecordingRequest, base::Unretained(this)));
registry_->AddInterface<mojom::StreamFactory>(base::BindRepeating(
&Service::BindStreamFactoryRequest, base::Unretained(this)));
if (device_notifier_enabled_) {
if (enable_remote_client_support_) {
registry_->AddInterface<mojom::DeviceNotifier>(base::BindRepeating(
&Service::BindDeviceNotifierRequest, base::Unretained(this)));
registry_->AddInterface<mojom::LogFactoryManager>(base::BindRepeating(
&Service::BindLogFactoryManagerRequest, base::Unretained(this)));
}
}
......@@ -160,7 +170,7 @@ void Service::BindStreamFactoryRequest(mojom::StreamFactoryRequest request) {
void Service::BindDeviceNotifierRequest(mojom::DeviceNotifierRequest request) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(ref_factory_);
DCHECK(device_notifier_enabled_);
DCHECK(enable_remote_client_support_);
if (!system_monitor_) {
CHECK(!base::SystemMonitor::Get());
......@@ -174,6 +184,17 @@ void Service::BindDeviceNotifierRequest(mojom::DeviceNotifierRequest request) {
"audio::DeviceNotifier Binding"));
}
void Service::BindLogFactoryManagerRequest(
mojom::LogFactoryManagerRequest request) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(ref_factory_);
DCHECK(log_factory_manager_);
DCHECK(enable_remote_client_support_);
log_factory_manager_->Bind(
std::move(request), TracedServiceRef(ref_factory_->CreateRef(),
"audio::LogFactoryManager Binding"));
}
void Service::MaybeRequestQuitDelayed() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
metrics_->HasNoConnections();
......
......@@ -16,6 +16,7 @@
#include "build/build_config.h"
#include "services/audio/public/mojom/debug_recording.mojom.h"
#include "services/audio/public/mojom/device_notifications.mojom.h"
#include "services/audio/public/mojom/log_factory_manager.mojom.h"
#include "services/audio/public/mojom/stream_factory.mojom.h"
#include "services/audio/public/mojom/system_info.mojom.h"
#include "services/audio/stream_factory.h"
......@@ -29,6 +30,7 @@ class SystemMonitor;
namespace media {
class AudioDeviceListenerMac;
class AudioManager;
class AudioLogFactory;
} // namespace media
namespace service_manager {
......@@ -38,6 +40,7 @@ class ServiceContextRefFactory;
namespace audio {
class DebugRecording;
class DeviceNotifier;
class LogFactoryManager;
class ServiceMetrics;
class SystemInfo;
......@@ -55,16 +58,22 @@ class Service : public service_manager::Service {
// Returns a pointer to AudioManager.
virtual media::AudioManager* GetAudioManager() = 0;
// Attempts to associate |factory| with the audio manager.
// |factory| must outlive the audio manager.
// It only makes sense to call this method before GetAudioManager().
virtual void SetAudioLogFactory(media::AudioLogFactory* factory) = 0;
};
// Service will attempt to quit if there are no connections to it within
// |quit_timeout| interval. If |quit_timeout| is base::TimeDelta() the
// service never quits. If |device_notifier_enabled| is true, the service
// service never quits. If |enable_remote_client_support| is true, the service
// will make available a DeviceNotifier object that allows clients to
// subscribe to notifications about device changes.
// subscribe to notifications about device changes and a LogFactoryManager
// object that allows clients to set a factory for audio logs.
Service(std::unique_ptr<AudioManagerAccessor> audio_manager_accessor,
base::TimeDelta quit_timeout,
bool device_notifier_enabled,
bool enable_remote_client_support,
std::unique_ptr<service_manager::BinderRegistry> registry);
~Service() final;
......@@ -82,6 +91,7 @@ class Service : public service_manager::Service {
void BindDebugRecordingRequest(mojom::DebugRecordingRequest request);
void BindStreamFactoryRequest(mojom::StreamFactoryRequest request);
void BindDeviceNotifierRequest(mojom::DeviceNotifierRequest request);
void BindLogFactoryManagerRequest(mojom::LogFactoryManagerRequest request);
void MaybeRequestQuitDelayed();
void MaybeRequestQuit();
......@@ -103,7 +113,7 @@ class Service : public service_manager::Service {
base::OneShotTimer quit_timer_;
std::unique_ptr<AudioManagerAccessor> audio_manager_accessor_;
const bool device_notifier_enabled_;
const bool enable_remote_client_support_;
std::unique_ptr<base::SystemMonitor> system_monitor_;
#if defined(OS_MACOSX)
std::unique_ptr<media::AudioDeviceListenerMac> audio_device_listener_mac_;
......@@ -112,6 +122,7 @@ class Service : public service_manager::Service {
std::unique_ptr<DebugRecording> debug_recording_;
base::Optional<StreamFactory> stream_factory_;
std::unique_ptr<DeviceNotifier> device_notifier_;
std::unique_ptr<LogFactoryManager> log_factory_manager_;
std::unique_ptr<ServiceMetrics> metrics_;
std::unique_ptr<service_manager::BinderRegistry> registry_;
......
......@@ -69,7 +69,7 @@ std::unique_ptr<service_manager::Service> CreateStandaloneService(
return std::make_unique<Service>(
std::make_unique<audio::OwningAudioManagerAccessor>(
base::BindOnce(&media::AudioManager::Create)),
GetQuitTimeout(), true /* enable_device_notifications */,
GetQuitTimeout(), true /* enable_remote_client_support */,
std::move(registry));
}
......
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