Commit 5772174d authored by Olga Sharonova's avatar Olga Sharonova Committed by Commit Bot

Standalone Audio service infrastructure

* OwningAudioManagerAccessor

* ServiceMain()

* Test fixture for out-of-process tests; used only for lifetime tests at this point.

* ServiceTest modification to allow custom test-specific manifests: we need that to
be able to have both in-process and out-of-process tests for the service. Done
following rockot@'s detailed instructions, see [1]

* kAudioServiceQuitTimeoutMs media switch to allow a non-default Audio service quit
timeout value (used in tests).

At this point we do not run Audio service out-of-process in Chrome: it's only an
basic infrastructure to enable testing various out-of-process functionality, such
as on crash behavior.

[1] https://www.google.com/url?hl=en&q=https://groups.google.com/a/chromium.org/d/msgid/services-dev/CAHri2_SHP26hm-a-295OCX5fMQZQqpopDxqLzi%252BpZXLzVnVN1w%2540mail.gmail.com?utm_medium%3Demail%26utm_source%3Dfooter&source=gmail&ust=1521721921151000&usg=AFQjCNH-pgZMrFjovDxxAE9ejd9v0eHHZg

Change-Id: I3af4760b1dedaa9211c135d5b11d33e78da772ac
Bug: 672469
Reviewed-on: https://chromium-review.googlesource.com/973861
Commit-Queue: Olga Sharonova <olka@chromium.org>
Reviewed-by: default avatarDale Curtis <dalecurtis@chromium.org>
Reviewed-by: default avatarMax Morin <maxmorin@chromium.org>
Reviewed-by: default avatarKen Rockot <rockot@chromium.org>
Cr-Commit-Position: refs/heads/master@{#546477}
parent 5d797d36
......@@ -12,6 +12,10 @@ namespace switches {
// Allow users to specify a custom buffer size for debugging purpose.
const char kAudioBufferSize[] = "audio-buffer-size";
// Set a timeout (in milliseconds) for the audio service to quit if there are no
// client connections to it. If the value is zero the service never quits.
const char kAudioServiceQuitTimeoutMs[] = "audio-service-quit-timeout-ms";
// Command line flag name to set the autoplay policy.
const char kAutoplayPolicy[] = "autoplay-policy";
......
......@@ -22,6 +22,8 @@ namespace switches {
MEDIA_EXPORT extern const char kAudioBufferSize[];
MEDIA_EXPORT extern const char kAudioServiceQuitTimeoutMs[];
MEDIA_EXPORT extern const char kAutoplayPolicy[];
MEDIA_EXPORT extern const char kDisableAudioOutput[];
......
......@@ -8,6 +8,21 @@ import("//services/service_manager/public/service_manifest.gni")
import("//services/service_manager/public/tools/test/service_test.gni")
import("//testing/test.gni")
# Currently standalone service binaries are not supported on Android or iOS.
standalone_supported = !(is_android || is_ios)
service("audio") {
sources = [
"service_main.cc",
]
deps = [
":lib",
"//services/audio/public/cpp",
"//services/audio/public/mojom",
]
}
service_manifest("manifest") {
name = "audio"
source = "manifest.json"
......@@ -21,6 +36,8 @@ source_set("lib") {
"in_process_audio_manager_accessor.h",
"output_stream.cc",
"output_stream.h",
"owning_audio_manager_accessor.cc",
"owning_audio_manager_accessor.h",
"service.cc",
"service.h",
"service_factory.cc",
......@@ -57,6 +74,7 @@ source_set("tests") {
]
deps = [
":audio",
":lib",
"//base/test:test_support",
"//media:test_support",
......@@ -70,8 +88,18 @@ source_set("tests") {
"//testing/gmock",
"//testing/gtest",
]
if (standalone_supported) {
sources += [ "test/standalone_service_test.cc" ]
deps += [ ":standalone_unittest_catalog_source" ]
}
data_deps = [
":audio",
]
}
# Embedded tests support.
service_manifest("unittest_manifest") {
name = "audio_unittests"
source = "test/service_unittest_manifest.json"
......@@ -82,3 +110,21 @@ catalog("tests_catalog") {
testonly = true
embedded_services = [ ":unittest_manifest" ]
}
# Standalone tests support.
if (standalone_supported) {
service_manifest("standalone_unittest_manifest") {
name = "audio_unittests"
source = "test/service_unittest_manifest.json"
}
catalog("standalone_unittest_catalog") {
embedded_services = [ ":standalone_unittest_manifest" ]
standalone_services = [ ":manifest" ]
}
catalog_cpp_source("standalone_unittest_catalog_source") {
catalog = ":standalone_unittest_catalog"
generated_function_name = "audio::CreateStandaloneUnittestCatalog"
}
}
// 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/owning_audio_manager_accessor.h"
#include "base/macros.h"
#include "base/single_thread_task_runner.h"
#include "media/audio/audio_manager.h"
#include "media/audio/audio_thread.h"
namespace audio {
namespace {
// Thread class for hosting owned AudioManager on the main thread of the
// service.
class MainThread : public media::AudioThread {
public:
MainThread();
~MainThread() override;
// AudioThread implementation.
void Stop() override;
base::SingleThreadTaskRunner* GetTaskRunner() override;
base::SingleThreadTaskRunner* GetWorkerTaskRunner() override;
private:
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
DISALLOW_COPY_AND_ASSIGN(MainThread);
};
MainThread::MainThread() : task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
MainThread::~MainThread() {
DCHECK(task_runner_->BelongsToCurrentThread());
}
void MainThread::Stop() {
DCHECK(task_runner_->BelongsToCurrentThread());
}
base::SingleThreadTaskRunner* MainThread::GetTaskRunner() {
return task_runner_.get();
}
base::SingleThreadTaskRunner* MainThread::GetWorkerTaskRunner() {
NOTREACHED();
return task_runner_.get();
}
} // namespace
OwningAudioManagerAccessor::OwningAudioManagerAccessor(
AudioManagerFactoryCallback audio_manager_factory_cb)
: audio_manager_factory_cb_(std::move(audio_manager_factory_cb)) {
DCHECK(audio_manager_factory_cb_);
}
OwningAudioManagerAccessor::~OwningAudioManagerAccessor() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
}
media::AudioManager* OwningAudioManagerAccessor::GetAudioManager() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (!audio_manager_) {
DCHECK(audio_manager_factory_cb_);
// TODO(http://crbug/812557): pass AudioLogFactory (needed for output
// streams).
audio_manager_ = std::move(audio_manager_factory_cb_)
.Run(std::make_unique<MainThread>(), nullptr);
DCHECK(audio_manager_);
}
DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
return audio_manager_.get();
}
void OwningAudioManagerAccessor::Shutdown() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (audio_manager_)
audio_manager_->Shutdown();
audio_manager_factory_cb_ = AudioManagerFactoryCallback();
}
} // 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_OWNING_AUDIO_MANAGER_ACCESSOR_H_
#define SERVICES_AUDIO_OWNING_AUDIO_MANAGER_ACCESSOR_H_
#include "base/macros.h"
#include "base/threading/thread_checker.h"
#include "services/audio/service.h"
namespace media {
class AudioLogFactory;
class AudioManager;
class AudioThread;
} // namespace media
namespace audio {
// Lazily creates AudioManager using provided factory callback and controls its
// lifetime. Threading model of a created AudioManager is enforced: its main
// thread is the thread OwningAudioManagerAccessor lives on.
class OwningAudioManagerAccessor : public Service::AudioManagerAccessor {
public:
using AudioManagerFactoryCallback =
base::OnceCallback<std::unique_ptr<media::AudioManager>(
std::unique_ptr<media::AudioThread>,
media::AudioLogFactory* audio_log_factory)>;
explicit OwningAudioManagerAccessor(
AudioManagerFactoryCallback audio_manager_factory_cb);
~OwningAudioManagerAccessor() override;
media::AudioManager* GetAudioManager() final;
void Shutdown() final;
private:
AudioManagerFactoryCallback audio_manager_factory_cb_;
std::unique_ptr<media::AudioManager> audio_manager_;
THREAD_CHECKER(thread_checker_);
DISALLOW_COPY_AND_ASSIGN(OwningAudioManagerAccessor);
};
} // namespace audio
#endif // SERVICES_AUDIO_OWNING_AUDIO_MANAGER_ACCESSOR_H_
......@@ -37,7 +37,8 @@ class Service : public service_manager::Service {
public:
virtual ~AudioManagerAccessor() {}
// Must be called before destruction.
// Must be called before destruction to cleanly shut down AudioManager.
// Service must ensure AudioManager is not called after that.
virtual void Shutdown() = 0;
// Returns a pointer to AudioManager.
......@@ -67,8 +68,8 @@ class Service : public service_manager::Service {
void MaybeRequestQuitDelayed();
void MaybeRequestQuit();
// Thread it runs on should be the same as the main thread of AudioManager
// provided by AudioManagerAccessor.
// The thread Service runs on should be the same as the main thread of
// AudioManager provided by AudioManagerAccessor.
THREAD_CHECKER(thread_checker_);
// The members below should outlive |ref_factory_|.
......
// 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 "base/command_line.h"
#include "base/strings/string_number_conversions.h"
#include "media/audio/audio_manager.h"
#include "media/base/media_switches.h"
#include "services/audio/owning_audio_manager_accessor.h"
#include "services/audio/service.h"
#include "services/service_manager/public/c/main.h"
#include "services/service_manager/public/cpp/service_runner.h"
namespace {
base::TimeDelta GetQuitTimeout() {
constexpr base::TimeDelta kDefaultTimeout = base::TimeDelta::FromSeconds(10);
const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
if (!cmd_line->HasSwitch(switches::kAudioServiceQuitTimeoutMs))
return kDefaultTimeout;
std::string timeout_str(
cmd_line->GetSwitchValueASCII(switches::kAudioServiceQuitTimeoutMs));
int timeout_ms = 0;
if (!base::StringToInt(timeout_str, &timeout_ms) || timeout_ms < 0)
return kDefaultTimeout; // Ill-formed value provided, fall back to default.
return base::TimeDelta::FromMilliseconds(timeout_ms);
}
} // namespace
MojoResult ServiceMain(MojoHandle service_request_handle) {
return service_manager::ServiceRunner(
new audio::Service(
std::make_unique<audio::OwningAudioManagerAccessor>(
base::BindOnce(&media::AudioManager::Create)),
GetQuitTimeout()))
.Run(service_request_handle);
}
// 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 "base/command_line.h"
#include "base/strings/string_number_conversions.h"
#include "media/base/media_switches.h"
#include "services/audio/service.h"
#include "services/audio/standalone_unittest_catalog_source.h"
#include "services/audio/test/service_lifetime_test_template.h"
#include "services/service_manager/public/cpp/service_context.h"
#include "services/service_manager/public/cpp/service_test.h"
namespace audio {
class StandaloneAudioServiceTest : public service_manager::test::ServiceTest {
public:
StandaloneAudioServiceTest() : ServiceTest("audio_unittests") {}
~StandaloneAudioServiceTest() override {}
protected:
// service_manager::test::ServiceTest:
std::unique_ptr<base::Value> CreateCustomTestCatalog() override {
return audio::CreateStandaloneUnittestCatalog();
}
void SetUp() override {
ServiceTest::SetUp();
base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
cmd_line->AppendSwitchASCII(switches::kAudioServiceQuitTimeoutMs,
base::UintToString(10));
}
private:
DISALLOW_COPY_AND_ASSIGN(StandaloneAudioServiceTest);
};
INSTANTIATE_TYPED_TEST_CASE_P(StandaloneAudioService,
ServiceLifetimeTestTemplate,
StandaloneAudioServiceTest);
} // namespace audio
......@@ -48,6 +48,10 @@ std::unique_ptr<Service> ServiceTest::CreateService() {
return std::make_unique<ServiceTestClient>(this);
}
std::unique_ptr<base::Value> ServiceTest::CreateCustomTestCatalog() {
return nullptr;
}
void ServiceTest::OnStartCalled(Connector* connector,
const std::string& name,
const std::string& user_id) {
......@@ -59,8 +63,8 @@ void ServiceTest::OnStartCalled(Connector* connector,
void ServiceTest::SetUp() {
background_service_manager_ =
std::make_unique<service_manager::BackgroundServiceManager>(nullptr,
nullptr);
std::make_unique<service_manager::BackgroundServiceManager>(
nullptr, CreateCustomTestCatalog());
// Create the service manager connection. We don't proceed until we get our
// Service's OnStart() method is called.
......
......@@ -82,6 +82,10 @@ class ServiceTest : public testing::Test {
// work.
virtual std::unique_ptr<Service> CreateService();
// By default returns null, which means the global default is used. Override
// to customize.
virtual std::unique_ptr<base::Value> CreateCustomTestCatalog();
// Call to set OnStart() metadata when GetService() is overridden.
void OnStartCalled(Connector* connector,
const std::string& name,
......
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