Commit 24e8a9cc authored by Becca Hughes's avatar Becca Hughes Committed by Commit Bot

[Media Session] Add a MediaController

Add a MediaController that can be used to proxy
commands to a MediaSession. Also adds a
MediaControllerFactory for creating them over
mojo.

BUG=893296

Change-Id: I82a7cb5798094486a28517dc5a18112ec8d14871
Reviewed-on: https://chromium-review.googlesource.com/c/1269623Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarTommy Steimel <steimel@chromium.org>
Commit-Queue: Becca Hughes <beccahughes@chromium.org>
Cr-Commit-Position: refs/heads/master@{#600799}
parent c2433fd3
...@@ -16,6 +16,8 @@ source_set("lib") { ...@@ -16,6 +16,8 @@ source_set("lib") {
"audio_focus_manager.h", "audio_focus_manager.h",
"audio_focus_manager_metrics_helper.cc", "audio_focus_manager_metrics_helper.cc",
"audio_focus_manager_metrics_helper.h", "audio_focus_manager_metrics_helper.h",
"media_controller.cc",
"media_controller.h",
"media_session_service.cc", "media_session_service.cc",
"media_session_service.h", "media_session_service.h",
] ]
...@@ -43,6 +45,7 @@ source_set("tests") { ...@@ -43,6 +45,7 @@ source_set("tests") {
testonly = true testonly = true
sources = [ sources = [
"audio_focus_manager_unittest.cc", "audio_focus_manager_unittest.cc",
"media_controller_unittest.cc",
"media_session_service_unittest.cc", "media_session_service_unittest.cc",
"mock_media_session.cc", "mock_media_session.cc",
"mock_media_session.h", "mock_media_session.h",
......
...@@ -201,12 +201,16 @@ void AudioFocusManager::AbandonAudioFocusInternal(RequestId id) { ...@@ -201,12 +201,16 @@ void AudioFocusManager::AbandonAudioFocusInternal(RequestId id) {
observers_.ForAllPtrs([&row](mojom::AudioFocusObserver* observer) { observers_.ForAllPtrs([&row](mojom::AudioFocusObserver* observer) {
observer->OnFocusLost(row->info().Clone()); observer->OnFocusLost(row->info().Clone());
}); });
DidChangeFocus();
return; return;
} }
if (IsAudioFocusEnforcementEnabled()) if (IsAudioFocusEnforcementEnabled())
EnforceAudioFocusAbandon(row->audio_focus_type()); EnforceAudioFocusAbandon(row->audio_focus_type());
DidChangeFocus();
// Notify observers that we lost audio focus. // Notify observers that we lost audio focus.
observers_.ForAllPtrs([&row](mojom::AudioFocusObserver* observer) { observers_.ForAllPtrs([&row](mojom::AudioFocusObserver* observer) {
observer->OnFocusLost(row->info().Clone()); observer->OnFocusLost(row->info().Clone());
...@@ -236,11 +240,10 @@ void AudioFocusManager::BindToDebugInterface( ...@@ -236,11 +240,10 @@ void AudioFocusManager::BindToDebugInterface(
debug_bindings_.AddBinding(this, std::move(request)); debug_bindings_.AddBinding(this, std::move(request));
} }
void AudioFocusManager::CloseAllMojoObjects() { void AudioFocusManager::BindToActiveControllerInterface(
mojom::MediaControllerRequest request) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
observers_.CloseAll(); active_media_controller_.BindToInterface(std::move(request));
bindings_.CloseAllBindings();
debug_bindings_.CloseAllBindings();
} }
void AudioFocusManager::RequestAudioFocusInternal( void AudioFocusManager::RequestAudioFocusInternal(
...@@ -257,6 +260,8 @@ void AudioFocusManager::RequestAudioFocusInternal( ...@@ -257,6 +260,8 @@ void AudioFocusManager::RequestAudioFocusInternal(
row->SetAudioFocusType(type); row->SetAudioFocusType(type);
audio_focus_stack_.push_back(std::move(row)); audio_focus_stack_.push_back(std::move(row));
DidChangeFocus();
// Notify observers that we were gained audio focus. // Notify observers that we were gained audio focus.
mojom::MediaSessionInfoPtr session_info = mojom::MediaSessionInfoPtr session_info =
audio_focus_stack_.back()->info().Clone(); audio_focus_stack_.back()->info().Clone();
...@@ -340,15 +345,17 @@ void AudioFocusManager::EnforceAudioFocusAbandon(mojom::AudioFocusType type) { ...@@ -340,15 +345,17 @@ void AudioFocusManager::EnforceAudioFocusAbandon(mojom::AudioFocusType type) {
} }
} }
void AudioFocusManager::DidChangeFocus() {
active_media_controller_.SetMediaSession(
audio_focus_stack_.empty() ? nullptr
: audio_focus_stack_.back()->session());
}
AudioFocusManager::AudioFocusManager() { AudioFocusManager::AudioFocusManager() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
} }
AudioFocusManager::~AudioFocusManager() { AudioFocusManager::~AudioFocusManager() = default;
DCHECK(observers_.empty());
DCHECK(bindings_.empty());
DCHECK(debug_bindings_.empty());
}
std::unique_ptr<AudioFocusManager::StackRow> std::unique_ptr<AudioFocusManager::StackRow>
AudioFocusManager::RemoveFocusEntryIfPresent(RequestId id) { AudioFocusManager::RemoveFocusEntryIfPresent(RequestId id) {
......
...@@ -14,7 +14,9 @@ ...@@ -14,7 +14,9 @@
#include "mojo/public/cpp/bindings/binding_set.h" #include "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/bindings/interface_ptr.h" #include "mojo/public/cpp/bindings/interface_ptr.h"
#include "mojo/public/cpp/bindings/interface_ptr_set.h" #include "mojo/public/cpp/bindings/interface_ptr_set.h"
#include "services/media_session/media_controller.h"
#include "services/media_session/public/mojom/audio_focus.mojom.h" #include "services/media_session/public/mojom/audio_focus.mojom.h"
#include "services/media_session/public/mojom/media_controller.mojom.h"
namespace base { namespace base {
class UnguessableToken; class UnguessableToken;
...@@ -26,6 +28,8 @@ namespace test { ...@@ -26,6 +28,8 @@ namespace test {
class MockMediaSession; class MockMediaSession;
} // namespace test } // namespace test
class MediaController;
class AudioFocusManager : public mojom::AudioFocusManager, class AudioFocusManager : public mojom::AudioFocusManager,
public mojom::AudioFocusManagerDebug { public mojom::AudioFocusManagerDebug {
public: public:
...@@ -55,12 +59,12 @@ class AudioFocusManager : public mojom::AudioFocusManager, ...@@ -55,12 +59,12 @@ class AudioFocusManager : public mojom::AudioFocusManager,
// Bind to a mojom::AudioFocusManagerDebugRequest. // Bind to a mojom::AudioFocusManagerDebugRequest.
void BindToDebugInterface(mojom::AudioFocusManagerDebugRequest request); void BindToDebugInterface(mojom::AudioFocusManagerDebugRequest request);
// This will close all Mojo bindings and interface pointers. This should be // Bind to a mojom::MediaControllerRequest.
// called by the MediaSession service before it is destroyed. void BindToActiveControllerInterface(mojom::MediaControllerRequest request);
void CloseAllMojoObjects();
private: private:
friend class AudioFocusManagerTest; friend class AudioFocusManagerTest;
friend class MediaControllerTest;
friend class test::MockMediaSession; friend class test::MockMediaSession;
// StackRow is an AudioFocusRequestClient and allows a media session to // StackRow is an AudioFocusRequestClient and allows a media session to
...@@ -84,6 +88,9 @@ class AudioFocusManager : public mojom::AudioFocusManager, ...@@ -84,6 +88,9 @@ class AudioFocusManager : public mojom::AudioFocusManager,
void AbandonAudioFocusInternal(RequestId); void AbandonAudioFocusInternal(RequestId);
void EnforceAudioFocusAbandon(mojom::AudioFocusType); void EnforceAudioFocusAbandon(mojom::AudioFocusType);
// Called when the active media session with audio focus changes.
void DidChangeFocus();
std::unique_ptr<StackRow> RemoveFocusEntryIfPresent(RequestId id); std::unique_ptr<StackRow> RemoveFocusEntryIfPresent(RequestId id);
// Returns the source name of the binding currently accessing the Audio // Returns the source name of the binding currently accessing the Audio
...@@ -93,6 +100,10 @@ class AudioFocusManager : public mojom::AudioFocusManager, ...@@ -93,6 +100,10 @@ class AudioFocusManager : public mojom::AudioFocusManager,
bool IsSessionOnTopOfAudioFocusStack(RequestId id, bool IsSessionOnTopOfAudioFocusStack(RequestId id,
mojom::AudioFocusType type) const; mojom::AudioFocusType type) const;
// This |MediaController| acts as a proxy for controlling the active
// |MediaSession| over mojo.
MediaController active_media_controller_;
// Holds mojo bindings for the Audio Focus Manager API. // Holds mojo bindings for the Audio Focus Manager API.
mojo::BindingSet<mojom::AudioFocusManager, std::unique_ptr<BindingContext>> mojo::BindingSet<mojom::AudioFocusManager, std::unique_ptr<BindingContext>>
bindings_; bindings_;
......
...@@ -9,7 +9,8 @@ ...@@ -9,7 +9,8 @@
"provides": { "provides": {
"app": [ "app": [
"media_session.mojom.AudioFocusManager", "media_session.mojom.AudioFocusManager",
"media_session.mojom.AudioFocusManagerDebug" "media_session.mojom.AudioFocusManagerDebug",
"media_session.mojom.MediaController"
], ],
"tests": [ "*" ] "tests": [ "*" ]
} }
......
// 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/media_session/media_controller.h"
namespace media_session {
MediaController::MediaController() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
MediaController::~MediaController() = default;
void MediaController::Suspend() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (session_)
session_->Suspend(mojom::MediaSession::SuspendType::kUI);
}
void MediaController::SetMediaSession(mojom::MediaSession* session) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
session_ = session;
}
void MediaController::BindToInterface(mojom::MediaControllerRequest request) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
bindings_.AddBinding(this, std::move(request));
}
void MediaController::FlushForTesting() {
bindings_.FlushForTesting();
}
} // namespace media_session
// 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_MEDIA_SESSION_MEDIA_CONTROLLER_H_
#define SERVICES_MEDIA_SESSION_MEDIA_CONTROLLER_H_
#include <memory>
#include "base/sequence_checker.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "services/media_session/public/mojom/media_controller.mojom.h"
#include "services/media_session/public/mojom/media_session.mojom.h"
namespace media_session {
// MediaController provides a control surface over Mojo for controlling a
// specific MediaSession. If |session_| is nullptr then all commands will be
// dropped.
class MediaController : public mojom::MediaController {
public:
MediaController();
~MediaController() override;
// mojom::MediaController overrides.
void Suspend() override;
void SetMediaSession(mojom::MediaSession*);
void BindToInterface(mojom::MediaControllerRequest);
void FlushForTesting();
private:
// Holds mojo bindings for mojom::MediaController.
mojo::BindingSet<mojom::MediaController> bindings_;
// Raw pointer to the local proxy. This is used for sending control events to
// the underlying MediaSession.
mojom::MediaSession* session_ = nullptr;
// Protects |session_| as it is not thread safe.
SEQUENCE_CHECKER(sequence_checker_);
DISALLOW_COPY_AND_ASSIGN(MediaController);
};
} // namespace media_session
#endif // SERVICES_MEDIA_SESSION_MEDIA_CONTROLLER_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/media_session/media_controller.h"
#include <memory>
#include <utility>
#include <vector>
#include "base/run_loop.h"
#include "base/test/scoped_task_environment.h"
#include "services/media_session/media_session_service.h"
#include "services/media_session/mock_media_session.h"
#include "services/service_manager/public/cpp/test/test_connector_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media_session {
class MediaControllerTest : public testing::Test {
public:
MediaControllerTest() = default;
void SetUp() override {
// Create an instance of the MediaSessionService.
connector_factory_ =
service_manager::TestConnectorFactory::CreateForUniqueService(
MediaSessionService::Create());
connector_ = connector_factory_->CreateConnector();
// Bind |audio_focus_ptr_| to AudioFocusManager.
connector_->BindInterface("test", mojo::MakeRequest(&audio_focus_ptr_));
// Bind |media_controller_ptr_| to MediaController.
connector_->BindInterface("test",
mojo::MakeRequest(&media_controller_ptr_));
}
void TearDown() override {
// Run pending tasks.
base::RunLoop().RunUntilIdle();
}
void RequestAudioFocus(test::MockMediaSession& session) {
session.RequestAudioFocusFromService(audio_focus_ptr_,
mojom::AudioFocusType::kGainTransient);
}
mojom::MediaControllerPtr& controller() { return media_controller_ptr_; }
private:
base::test::ScopedTaskEnvironment task_environment_;
std::unique_ptr<service_manager::TestConnectorFactory> connector_factory_;
std::unique_ptr<service_manager::Connector> connector_;
mojom::AudioFocusManagerPtr audio_focus_ptr_;
mojom::MediaControllerPtr media_controller_ptr_;
DISALLOW_COPY_AND_ASSIGN(MediaControllerTest);
};
TEST_F(MediaControllerTest, ActiveController_Suspend) {
test::MockMediaSession media_session;
{
test::MockMediaSessionMojoObserver observer(media_session);
RequestAudioFocus(media_session);
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kActive);
}
{
test::MockMediaSessionMojoObserver observer(media_session);
controller()->Suspend();
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kSuspended);
}
}
TEST_F(MediaControllerTest, ActiveController_Suspend_Multiple) {
test::MockMediaSession media_session_1;
{
test::MockMediaSessionMojoObserver observer(media_session_1);
RequestAudioFocus(media_session_1);
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kActive);
}
test::MockMediaSession media_session_2;
{
test::MockMediaSessionMojoObserver observer_1(media_session_1);
test::MockMediaSessionMojoObserver observer_2(media_session_2);
RequestAudioFocus(media_session_2);
observer_1.WaitForState(mojom::MediaSessionInfo::SessionState::kSuspended);
observer_2.WaitForState(mojom::MediaSessionInfo::SessionState::kActive);
}
{
test::MockMediaSessionMojoObserver observer(media_session_2);
controller()->Suspend();
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kSuspended);
}
{
test::MockMediaSessionMojoObserver observer(media_session_1);
media_session_2.AbandonAudioFocusFromClient();
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kActive);
}
{
test::MockMediaSessionMojoObserver observer(media_session_1);
controller()->Suspend();
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kSuspended);
}
}
TEST_F(MediaControllerTest, ActiveController_Suspend_Noop) {
controller()->Suspend();
}
TEST_F(MediaControllerTest, ActiveController_Suspend_Noop_Abandoned) {
test::MockMediaSession media_session;
{
test::MockMediaSessionMojoObserver observer(media_session);
RequestAudioFocus(media_session);
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kActive);
}
media_session.AbandonAudioFocusFromClient();
controller()->Suspend();
{
test::MockMediaSessionMojoObserver observer(media_session);
RequestAudioFocus(media_session);
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kActive);
}
}
} // namespace media_session
...@@ -17,9 +17,7 @@ std::unique_ptr<service_manager::Service> MediaSessionService::Create() { ...@@ -17,9 +17,7 @@ std::unique_ptr<service_manager::Service> MediaSessionService::Create() {
MediaSessionService::MediaSessionService() MediaSessionService::MediaSessionService()
: audio_focus_manager_(std::make_unique<AudioFocusManager>()) {} : audio_focus_manager_(std::make_unique<AudioFocusManager>()) {}
MediaSessionService::~MediaSessionService() { MediaSessionService::~MediaSessionService() = default;
audio_focus_manager_->CloseAllMojoObjects();
}
void MediaSessionService::OnStart() { void MediaSessionService::OnStart() {
ref_factory_.reset(new service_manager::ServiceContextRefFactory( ref_factory_.reset(new service_manager::ServiceContextRefFactory(
...@@ -32,6 +30,10 @@ void MediaSessionService::OnStart() { ...@@ -32,6 +30,10 @@ void MediaSessionService::OnStart() {
registry_.AddInterface( registry_.AddInterface(
base::BindRepeating(&AudioFocusManager::BindToDebugInterface, base::BindRepeating(&AudioFocusManager::BindToDebugInterface,
base::Unretained(audio_focus_manager_.get()))); base::Unretained(audio_focus_manager_.get())));
registry_.AddInterface(
base::BindRepeating(&AudioFocusManager::BindToActiveControllerInterface,
base::Unretained(audio_focus_manager_.get())));
} }
void MediaSessionService::OnBindInterface( void MediaSessionService::OnBindInterface(
......
...@@ -11,6 +11,33 @@ ...@@ -11,6 +11,33 @@
namespace media_session { namespace media_session {
namespace test { namespace test {
MockMediaSessionMojoObserver::MockMediaSessionMojoObserver(
mojom::MediaSession& media_session)
: binding_(this) {
mojom::MediaSessionObserverPtr observer;
binding_.Bind(mojo::MakeRequest(&observer));
media_session.AddObserver(std::move(observer));
}
MockMediaSessionMojoObserver::~MockMediaSessionMojoObserver() = default;
void MockMediaSessionMojoObserver::MediaSessionInfoChanged(
mojom::MediaSessionInfoPtr session) {
session_info_ = std::move(session);
if (wanted_state_ == session_info_->state)
run_loop_.Quit();
}
void MockMediaSessionMojoObserver::WaitForState(
mojom::MediaSessionInfo::SessionState wanted_state) {
if (session_info_ && session_info_->state == wanted_state)
return;
wanted_state_ = wanted_state;
run_loop_.Run();
}
MockMediaSession::MockMediaSession() = default; MockMediaSession::MockMediaSession() = default;
MockMediaSession::MockMediaSession(bool force_duck) : force_duck_(force_duck) {} MockMediaSession::MockMediaSession(bool force_duck) : force_duck_(force_duck) {}
...@@ -18,7 +45,6 @@ MockMediaSession::MockMediaSession(bool force_duck) : force_duck_(force_duck) {} ...@@ -18,7 +45,6 @@ MockMediaSession::MockMediaSession(bool force_duck) : force_duck_(force_duck) {}
MockMediaSession::~MockMediaSession() {} MockMediaSession::~MockMediaSession() {}
void MockMediaSession::Suspend(SuspendType suspend_type) { void MockMediaSession::Suspend(SuspendType suspend_type) {
DCHECK_EQ(SuspendType::kSystem, suspend_type);
SetState(mojom::MediaSessionInfo::SessionState::kSuspended); SetState(mojom::MediaSessionInfo::SessionState::kSuspended);
} }
...@@ -42,7 +68,9 @@ void MockMediaSession::GetMediaSessionInfo( ...@@ -42,7 +68,9 @@ void MockMediaSession::GetMediaSessionInfo(
std::move(callback).Run(GetMediaSessionInfoSync()); std::move(callback).Run(GetMediaSessionInfoSync());
} }
void MockMediaSession::AddObserver(mojom::MediaSessionObserverPtr observer) {} void MockMediaSession::AddObserver(mojom::MediaSessionObserverPtr observer) {
observers_.AddPtr(std::move(observer));
}
void MockMediaSession::GetDebugInfo(GetDebugInfoCallback callback) { void MockMediaSession::GetDebugInfo(GetDebugInfoCallback callback) {
mojom::MediaSessionDebugInfoPtr debug_info( mojom::MediaSessionDebugInfoPtr debug_info(
...@@ -123,8 +151,14 @@ void MockMediaSession::SetState(mojom::MediaSessionInfo::SessionState state) { ...@@ -123,8 +151,14 @@ void MockMediaSession::SetState(mojom::MediaSessionInfo::SessionState state) {
} }
void MockMediaSession::NotifyObservers() { void MockMediaSession::NotifyObservers() {
mojom::MediaSessionInfoPtr session_info = GetMediaSessionInfoSync();
if (afr_client_.is_bound()) if (afr_client_.is_bound())
afr_client_->MediaSessionInfoChanged(GetMediaSessionInfoSync()); afr_client_->MediaSessionInfoChanged(session_info.Clone());
observers_.ForAllPtrs([&session_info](mojom::MediaSessionObserver* observer) {
observer->MediaSessionInfoChanged(session_info.Clone());
});
} }
mojom::MediaSessionInfoPtr MockMediaSession::GetMediaSessionInfoSync() const { mojom::MediaSessionInfoPtr MockMediaSession::GetMediaSessionInfoSync() const {
......
...@@ -5,7 +5,11 @@ ...@@ -5,7 +5,11 @@
#ifndef SERVICES_MEDIA_SESSION_MOCK_MEDIA_SESSION_H_ #ifndef SERVICES_MEDIA_SESSION_MOCK_MEDIA_SESSION_H_
#define SERVICES_MEDIA_SESSION_MOCK_MEDIA_SESSION_H_ #define SERVICES_MEDIA_SESSION_MOCK_MEDIA_SESSION_H_
#include "base/optional.h"
#include "base/run_loop.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/binding_set.h" #include "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/bindings/interface_ptr_set.h"
#include "services/media_session/public/mojom/audio_focus.mojom.h" #include "services/media_session/public/mojom/audio_focus.mojom.h"
#include "services/media_session/public/mojom/media_session.mojom.h" #include "services/media_session/public/mojom/media_session.mojom.h"
...@@ -16,6 +20,25 @@ class UnguessableToken; ...@@ -16,6 +20,25 @@ class UnguessableToken;
namespace media_session { namespace media_session {
namespace test { namespace test {
// A mock MediaSessionObsever that can be used for waiting for state changes.
class MockMediaSessionMojoObserver : public mojom::MediaSessionObserver {
public:
explicit MockMediaSessionMojoObserver(mojom::MediaSession& media_session);
~MockMediaSessionMojoObserver() override;
// mojom::MediaSessionObserver overrides.
void MediaSessionInfoChanged(mojom::MediaSessionInfoPtr session) override;
void WaitForState(mojom::MediaSessionInfo::SessionState wanted_state);
private:
mojom::MediaSessionInfoPtr session_info_;
base::Optional<mojom::MediaSessionInfo::SessionState> wanted_state_;
base::RunLoop run_loop_;
mojo::Binding<mojom::MediaSessionObserver> binding_;
};
// A mock MediaSession that can be used for interacting with the Media Session // A mock MediaSession that can be used for interacting with the Media Session
// service during tests. // service during tests.
class MockMediaSession : public mojom::MediaSession { class MockMediaSession : public mojom::MediaSession {
...@@ -63,6 +86,8 @@ class MockMediaSession : public mojom::MediaSession { ...@@ -63,6 +86,8 @@ class MockMediaSession : public mojom::MediaSession {
mojo::BindingSet<mojom::MediaSession> bindings_; mojo::BindingSet<mojom::MediaSession> bindings_;
mojo::InterfacePtrSet<mojom::MediaSessionObserver> observers_;
DISALLOW_COPY_AND_ASSIGN(MockMediaSession); DISALLOW_COPY_AND_ASSIGN(MockMediaSession);
}; };
......
...@@ -11,6 +11,7 @@ mojom_component("mojom") { ...@@ -11,6 +11,7 @@ mojom_component("mojom") {
sources = [ sources = [
"audio_focus.mojom", "audio_focus.mojom",
"constants.mojom", "constants.mojom",
"media_controller.mojom",
"media_session.mojom", "media_session.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 media_session.mojom;
// Controls a MediaSession. This will automatically route commands to the
// correct session if the audio focus changes. If the media session is
// not controllable then the commands will be no-ops.
interface MediaController {
// Suspend the media session.
Suspend();
};
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