Commit 684eae89 authored by Tommy Steimel's avatar Tommy Steimel Committed by Commit Bot

System Media Controls: Move MPRIS into shared component

This CL moves the MPRIS implementation into the SystemMediaControls
component. It deletes the usage of the MPRIS-specific API in favor of
the platform-agnostic SystemMediaControls API.

Public design doc:
https://docs.google.com/document/d/1_UjhXdXzQlPEwFKpogTZm-ILylKid4lTiOomqHv-IPg/edit?usp=sharing

Bug: 949596
Change-Id: I2af605dd742969fa474dfe14ec62167ebb80852b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1895385Reviewed-by: default avatarScott Violet <sky@chromium.org>
Commit-Queue: Tommy Steimel <steimel@chromium.org>
Cr-Commit-Position: refs/heads/master@{#711904}
parent 270e9847
......@@ -153,6 +153,7 @@ test("components_unittests") {
"//components/sync_bookmarks:unit_tests",
"//components/sync_preferences:unit_tests",
"//components/sync_user_events:unit_tests",
"//components/system_media_controls:unit_tests",
"//components/tab_count_metrics:unit_tests",
"//components/test:run_all_unittests",
"//components/translate/core/browser:unit_tests",
......
......@@ -2,7 +2,11 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("linux/buildflags/buildflags.gni")
component("system_media_controls") {
friend = [ ":unit_tests" ]
public = [
"system_media_controls.h",
"system_media_controls_observer.h",
......@@ -25,6 +29,17 @@ component("system_media_controls") {
"win/system_media_controls_win.cc",
"win/system_media_controls_win.h",
]
} else if (use_mpris) {
sources = [
"linux/system_media_controls_linux.cc",
"linux/system_media_controls_linux.h",
]
deps += [
"//build:branding_buildflags",
"//components/dbus/properties",
"//components/dbus/thread_linux",
"//dbus",
]
} else {
sources = [
"system_media_controls_stub.cc",
......@@ -32,6 +47,26 @@ component("system_media_controls") {
}
}
source_set("unit_tests") {
testonly = true
if (use_mpris) {
sources = [
"linux/system_media_controls_linux_unittest.cc",
]
deps = [
":system_media_controls",
"//base",
"//base/test:test_support",
"//components/dbus/thread_linux",
"//dbus",
"//dbus:test_support",
"//testing/gmock",
"//testing/gtest",
]
}
}
static_library("test_support") {
testonly = true
......
include_rules = [
"+components/dbus",
"+dbus",
"+third_party/skia",
"+ui/gfx",
]
......@@ -3,7 +3,7 @@
# found in the LICENSE file.
import("//build/buildflag_header.gni")
import("//ui/base/mpris/buildflags/buildflags.gni")
import("buildflags.gni")
buildflag_header("buildflags") {
header = "buildflags.h"
......
......@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_BASE_MPRIS_MPRIS_SERVICE_IMPL_H_
#define UI_BASE_MPRIS_MPRIS_SERVICE_IMPL_H_
#ifndef COMPONENTS_SYSTEM_MEDIA_CONTROLS_LINUX_SYSTEM_MEDIA_CONTROLS_LINUX_H_
#define COMPONENTS_SYSTEM_MEDIA_CONTROLS_LINUX_SYSTEM_MEDIA_CONTROLS_LINUX_H_
#include <string>
......@@ -14,9 +14,9 @@
#include "base/observer_list.h"
#include "base/timer/timer.h"
#include "components/dbus/properties/types.h"
#include "components/system_media_controls/system_media_controls.h"
#include "dbus/bus.h"
#include "dbus/exported_object.h"
#include "ui/base/mpris/mpris_service.h"
class DbusProperties;
......@@ -24,32 +24,53 @@ namespace dbus {
class MethodCall;
} // namespace dbus
namespace mpris {
namespace system_media_controls {
class MprisServiceObserver;
class SystemMediaControlsObserver;
namespace internal {
COMPONENT_EXPORT(SYSTEM_MEDIA_CONTROLS)
extern const char kMprisAPIServiceNamePrefix[];
COMPONENT_EXPORT(SYSTEM_MEDIA_CONTROLS) extern const char kMprisAPIObjectPath[];
COMPONENT_EXPORT(SYSTEM_MEDIA_CONTROLS)
extern const char kMprisAPIInterfaceName[];
COMPONENT_EXPORT(SYSTEM_MEDIA_CONTROLS)
extern const char kMprisAPIPlayerInterfaceName[];
// A D-Bus service conforming to the MPRIS spec:
// https://specifications.freedesktop.org/mpris-spec/latest/
class COMPONENT_EXPORT(MPRIS) MprisServiceImpl : public MprisService {
class COMPONENT_EXPORT(SYSTEM_MEDIA_CONTROLS) SystemMediaControlsLinux
: public SystemMediaControls {
public:
MprisServiceImpl();
~MprisServiceImpl() override;
static MprisServiceImpl* GetInstance();
// MprisService implementation.
void StartService() override;
void AddObserver(MprisServiceObserver* observer) override;
void RemoveObserver(MprisServiceObserver* observer) override;
void SetCanGoNext(bool value) override;
void SetCanGoPrevious(bool value) override;
void SetCanPlay(bool value) override;
void SetCanPause(bool value) override;
SystemMediaControlsLinux();
~SystemMediaControlsLinux() override;
static SystemMediaControlsLinux* GetInstance();
// Starts the DBus service.
void StartService();
// SystemMediaControls implementation.
void AddObserver(SystemMediaControlsObserver* observer) override;
void RemoveObserver(SystemMediaControlsObserver* observer) override;
void SetEnabled(bool enabled) override {}
void SetIsNextEnabled(bool value) override;
void SetIsPreviousEnabled(bool value) override;
void SetIsPlayEnabled(bool value) override;
void SetIsPauseEnabled(bool value) override;
void SetIsStopEnabled(bool value) override {}
void SetPlaybackStatus(PlaybackStatus value) override;
void SetTitle(const base::string16& value) override;
void SetArtist(const base::string16& value) override;
void SetAlbum(const base::string16& value) override;
std::string GetServiceName() const override;
void SetThumbnail(const SkBitmap& bitmap) override {}
void ClearThumbnail() override {}
void ClearMetadata() override;
void UpdateDisplay() override {}
// Returns the generated service name.
std::string GetServiceName() const;
// Used for testing with a mock DBus Bus.
void SetBusForTesting(scoped_refptr<dbus::Bus> bus) { bus_ = bus; }
......@@ -96,14 +117,19 @@ class COMPONENT_EXPORT(MPRIS) MprisServiceImpl : public MprisService {
base::RepeatingCallback<void(bool)> barrier_;
// True if we have started creating the DBus service.
bool started_ = false;
// True if we have finished creating the DBus service and received ownership.
bool service_ready_ = false;
base::ObserverList<MprisServiceObserver> observers_;
base::ObserverList<SystemMediaControlsObserver> observers_;
DISALLOW_COPY_AND_ASSIGN(MprisServiceImpl);
DISALLOW_COPY_AND_ASSIGN(SystemMediaControlsLinux);
};
} // namespace mpris
} // namespace internal
} // namespace system_media_controls
#endif // UI_BASE_MPRIS_MPRIS_SERVICE_IMPL_H_
#endif // COMPONENTS_SYSTEM_MEDIA_CONTROLS_LINUX_SYSTEM_MEDIA_CONTROLS_LINUX_H_
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/base/mpris/mpris_service_impl.h"
#include "components/system_media_controls/linux/system_media_controls_linux.h"
#include <memory>
......@@ -12,12 +12,12 @@
#include "base/strings/utf_string_conversions.h"
#include "base/test/task_environment.h"
#include "components/dbus/thread_linux/dbus_thread_linux.h"
#include "components/system_media_controls/system_media_controls_observer.h"
#include "dbus/message.h"
#include "dbus/mock_bus.h"
#include "dbus/mock_exported_object.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/mpris/mpris_service_observer.h"
using ::testing::_;
using ::testing::Invoke;
......@@ -25,7 +25,9 @@ using ::testing::Return;
using ::testing::Unused;
using ::testing::WithArg;
namespace mpris {
namespace system_media_controls {
namespace internal {
namespace {
......@@ -33,12 +35,12 @@ constexpr uint32_t kFakeSerial = 123;
} // anonymous namespace
class MockMprisServiceObserver : public MprisServiceObserver {
class MockSystemMediaControlsObserver : public SystemMediaControlsObserver {
public:
MockMprisServiceObserver() = default;
~MockMprisServiceObserver() override = default;
MockSystemMediaControlsObserver() = default;
~MockSystemMediaControlsObserver() override = default;
// MprisServiceObserver implementation.
// SystemMediaControlsObserver implementation.
MOCK_METHOD0(OnServiceReady, void());
MOCK_METHOD0(OnNext, void());
MOCK_METHOD0(OnPrevious, void());
......@@ -48,15 +50,16 @@ class MockMprisServiceObserver : public MprisServiceObserver {
MOCK_METHOD0(OnPlay, void());
};
class MprisServiceImplTest : public testing::Test, public MprisServiceObserver {
class SystemMediaControlsLinuxTest : public testing::Test,
public SystemMediaControlsObserver {
public:
MprisServiceImplTest()
SystemMediaControlsLinuxTest()
: task_environment_(base::test::TaskEnvironment::MainThreadType::UI) {}
~MprisServiceImplTest() override = default;
~SystemMediaControlsLinuxTest() override = default;
void SetUp() override { StartMprisServiceAndWaitForReady(); }
void AddObserver(MockMprisServiceObserver* observer) {
void AddObserver(MockSystemMediaControlsObserver* observer) {
service_->AddObserver(observer);
}
......@@ -71,12 +74,13 @@ class MprisServiceImplTest : public testing::Test, public MprisServiceObserver {
// Call the method and await a response.
player_interface_exported_methods_[method_name].Run(
&method_call, base::BindRepeating(&MprisServiceImplTest::OnResponse,
base::Unretained(this)));
&method_call,
base::BindRepeating(&SystemMediaControlsLinuxTest::OnResponse,
base::Unretained(this)));
response_wait_loop_->Run();
}
MprisService* GetService() { return service_.get(); }
SystemMediaControlsLinux* GetService() { return service_.get(); }
dbus::MockExportedObject* GetExportedObject() {
return mock_exported_object_.get();
......@@ -85,7 +89,7 @@ class MprisServiceImplTest : public testing::Test, public MprisServiceObserver {
private:
void StartMprisServiceAndWaitForReady() {
service_wait_loop_ = std::make_unique<base::RunLoop>();
service_ = std::make_unique<mpris::MprisServiceImpl>();
service_ = std::make_unique<SystemMediaControlsLinux>();
SetUpMocks();
......@@ -111,14 +115,15 @@ class MprisServiceImplTest : public testing::Test, public MprisServiceObserver {
GetExportedObject(dbus::ObjectPath(kMprisAPIObjectPath)))
.WillOnce(Return(mock_exported_object_.get()));
EXPECT_CALL(*mock_bus_, RequestOwnership(service_->GetServiceName(), _, _))
.WillOnce(Invoke(this, &MprisServiceImplTest::OnOwnership));
.WillOnce(Invoke(this, &SystemMediaControlsLinuxTest::OnOwnership));
// The service must call ShutdownAndBlock in order to properly clean up the
// DBus service.
EXPECT_CALL(*mock_bus_, ShutdownAndBlock());
EXPECT_CALL(*mock_exported_object_, ExportMethod(_, _, _, _))
.WillRepeatedly(Invoke(this, &MprisServiceImplTest::OnExported));
.WillRepeatedly(
Invoke(this, &SystemMediaControlsLinuxTest::OnExported));
}
// Tell the service that ownership was successful.
......@@ -146,74 +151,80 @@ class MprisServiceImplTest : public testing::Test, public MprisServiceObserver {
response_wait_loop_->Quit();
}
// mpris::MprisServiceObserver implementation.
// SystemMediaControlsObserver implementation.
void OnServiceReady() override {
if (service_wait_loop_)
service_wait_loop_->Quit();
}
void OnNext() override {}
void OnPrevious() override {}
void OnPlay() override {}
void OnPause() override {}
void OnPlayPause() override {}
void OnStop() override {}
base::test::TaskEnvironment task_environment_;
std::unique_ptr<base::RunLoop> service_wait_loop_;
std::unique_ptr<base::RunLoop> response_wait_loop_;
std::unique_ptr<MprisServiceImpl> service_;
std::unique_ptr<SystemMediaControlsLinux> service_;
scoped_refptr<dbus::MockBus> mock_bus_;
scoped_refptr<dbus::MockExportedObject> mock_exported_object_;
base::flat_map<std::string, dbus::ExportedObject::MethodCallCallback>
player_interface_exported_methods_;
DISALLOW_COPY_AND_ASSIGN(MprisServiceImplTest);
DISALLOW_COPY_AND_ASSIGN(SystemMediaControlsLinuxTest);
};
TEST_F(MprisServiceImplTest, ObserverNotifiedOfServiceReadyWhenAdded) {
MockMprisServiceObserver observer;
TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfServiceReadyWhenAdded) {
MockSystemMediaControlsObserver observer;
EXPECT_CALL(observer, OnServiceReady());
AddObserver(&observer);
}
TEST_F(MprisServiceImplTest, ObserverNotifiedOfNextCalls) {
MockMprisServiceObserver observer;
TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfNextCalls) {
MockSystemMediaControlsObserver observer;
EXPECT_CALL(observer, OnNext());
AddObserver(&observer);
CallMediaPlayer2PlayerMethodAndBlock("Next");
}
TEST_F(MprisServiceImplTest, ObserverNotifiedOfPreviousCalls) {
MockMprisServiceObserver observer;
TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfPreviousCalls) {
MockSystemMediaControlsObserver observer;
EXPECT_CALL(observer, OnPrevious());
AddObserver(&observer);
CallMediaPlayer2PlayerMethodAndBlock("Previous");
}
TEST_F(MprisServiceImplTest, ObserverNotifiedOfPauseCalls) {
MockMprisServiceObserver observer;
TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfPauseCalls) {
MockSystemMediaControlsObserver observer;
EXPECT_CALL(observer, OnPause());
AddObserver(&observer);
CallMediaPlayer2PlayerMethodAndBlock("Pause");
}
TEST_F(MprisServiceImplTest, ObserverNotifiedOfPlayPauseCalls) {
MockMprisServiceObserver observer;
TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfPlayPauseCalls) {
MockSystemMediaControlsObserver observer;
EXPECT_CALL(observer, OnPlayPause());
AddObserver(&observer);
CallMediaPlayer2PlayerMethodAndBlock("PlayPause");
}
TEST_F(MprisServiceImplTest, ObserverNotifiedOfStopCalls) {
MockMprisServiceObserver observer;
TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfStopCalls) {
MockSystemMediaControlsObserver observer;
EXPECT_CALL(observer, OnStop());
AddObserver(&observer);
CallMediaPlayer2PlayerMethodAndBlock("Stop");
}
TEST_F(MprisServiceImplTest, ObserverNotifiedOfPlayCalls) {
MockMprisServiceObserver observer;
TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfPlayCalls) {
MockSystemMediaControlsObserver observer;
EXPECT_CALL(observer, OnPlay());
AddObserver(&observer);
CallMediaPlayer2PlayerMethodAndBlock("Play");
}
TEST_F(MprisServiceImplTest, ChangingPropertyEmitsSignal) {
TEST_F(SystemMediaControlsLinuxTest, ChangingPropertyEmitsSignal) {
base::RunLoop wait_for_signal;
// The returned signal should give the changed property.
......@@ -250,14 +261,14 @@ TEST_F(MprisServiceImplTest, ChangingPropertyEmitsSignal) {
// CanPlay is initialized as false, so setting it to true should emit an
// org.freedesktop.DBus.Properties.PropertiesChanged signal.
GetService()->SetCanPlay(true);
GetService()->SetIsPlayEnabled(true);
wait_for_signal.Run();
// Setting it to true again should not re-signal.
GetService()->SetCanPlay(true);
GetService()->SetIsPlayEnabled(true);
}
TEST_F(MprisServiceImplTest, ChangingMetadataEmitsSignal) {
TEST_F(SystemMediaControlsLinuxTest, ChangingMetadataEmitsSignal) {
base::RunLoop wait_for_signal;
// The returned signal should give the changed property.
......@@ -313,4 +324,6 @@ TEST_F(MprisServiceImplTest, ChangingMetadataEmitsSignal) {
GetService()->SetTitle(base::ASCIIToUTF16("Foo"));
}
} // namespace mpris
} // namespace internal
} // namespace system_media_controls
......@@ -14,11 +14,17 @@ namespace system_media_controls {
class COMPONENT_EXPORT(SYSTEM_MEDIA_CONTROLS) SystemMediaControlsObserver
: public base::CheckedObserver {
public:
// Called when the service has completed setup. Also called when an observer
// is added if the service is already set up.
virtual void OnServiceReady() = 0;
// Called when the observer should handle the given control.
virtual void OnNext() = 0;
virtual void OnPrevious() = 0;
virtual void OnPlay() = 0;
virtual void OnPause() = 0;
virtual void OnPlayPause() = 0;
virtual void OnStop() = 0;
virtual void OnPlay() = 0;
protected:
~SystemMediaControlsObserver() override = default;
......
......@@ -120,6 +120,9 @@ bool SystemMediaControlsWin::Initialize() {
void SystemMediaControlsWin::AddObserver(
SystemMediaControlsObserver* observer) {
observers_.AddObserver(observer);
if (initialized_)
observer->OnServiceReady();
}
void SystemMediaControlsWin::RemoveObserver(
......
......@@ -17,7 +17,6 @@ import("//ppapi/buildflags/buildflags.gni")
import("//printing/buildflags/buildflags.gni")
import("//third_party/blink/public/public_features.gni")
import("//tools/ipc_fuzzer/ipc_fuzzer.gni")
import("//ui/base/mpris/buildflags/buildflags.gni")
jumbo_source_set("browser") {
# Only the public target should depend on this. All other targets (even
......@@ -219,7 +218,6 @@ jumbo_source_set("browser") {
"//ui/base/clipboard",
"//ui/base/idle",
"//ui/base/ime/init",
"//ui/base/mpris/buildflags",
"//ui/display",
"//ui/display/types",
"//ui/events",
......@@ -2666,14 +2664,6 @@ jumbo_source_set("browser") {
"gpu/viz_devtools_connector.h",
]
}
if (use_mpris) {
sources += [
"media/mpris_notifier.cc",
"media/mpris_notifier.h",
]
deps += [ "//ui/base/mpris" ]
}
}
buildflag_header("accessibility_buildflags") {
......
......@@ -14,12 +14,6 @@
#include "content/browser/media/system_media_controls_notifier.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/idle/idle.h"
#include "ui/base/mpris/buildflags/buildflags.h"
#if BUILDFLAG(USE_MPRIS)
#include "content/browser/media/mpris_notifier.h"
#include "ui/base/mpris/mpris_service.h" // nogncheck
#endif
#if defined(OS_MACOSX)
#include "content/browser/media/now_playing_info_center_notifier.h"
......@@ -180,13 +174,6 @@ void MediaKeysListenerManagerImpl::EnsureAuxiliaryServices() {
system_media_controls);
}
#if BUILDFLAG(USE_MPRIS)
mpris::MprisService::GetInstance()->StartService();
mpris_notifier_ = std::make_unique<MprisNotifier>(connector_);
mpris_notifier_->Initialize();
#endif
#if defined(OS_MACOSX)
// On Mac OS, we need to initialize the idle monitor in order to check if the
// system is locked.
......
......@@ -14,7 +14,6 @@
#include "content/common/content_export.h"
#include "content/public/browser/media_keys_listener_manager.h"
#include "ui/base/accelerators/media_keys_listener.h"
#include "ui/base/mpris/buildflags/buildflags.h"
#include "ui/events/keycodes/keyboard_codes.h"
namespace service_manager {
......@@ -30,10 +29,6 @@ class SystemMediaControlsNotifier;
class NowPlayingInfoCenterNotifier;
#endif
#if BUILDFLAG(USE_MPRIS)
class MprisNotifier;
#endif
// Listens for media keys and decides which listeners receive which events. In
// particular, it owns one of its delegates (HardwareKeyMediaController), and
// only propagates to the HardwareKeyMediaController if no other delegates are
......@@ -129,10 +124,6 @@ class CONTENT_EXPORT MediaKeysListenerManagerImpl
now_playing_info_center_notifier_;
#endif
#if BUILDFLAG(USE_MPRIS)
std::unique_ptr<MprisNotifier> mpris_notifier_;
#endif
DISALLOW_COPY_AND_ASSIGN(MediaKeysListenerManagerImpl);
};
......
// Copyright 2019 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 "content/browser/media/mpris_notifier.h"
#include <memory>
#include <utility>
#include "mojo/public/cpp/bindings/remote.h"
#include "services/media_session/public/mojom/constants.mojom.h"
#include "services/media_session/public/mojom/media_session.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
#include "ui/base/mpris/mpris_service.h"
namespace content {
MprisNotifier::MprisNotifier(service_manager::Connector* connector)
: connector_(connector) {}
MprisNotifier::~MprisNotifier() = default;
void MprisNotifier::Initialize() {
// |service_| can be set in tests.
if (!service_)
service_ = mpris::MprisService::GetInstance();
DCHECK(service_);
// |connector_| can be null in tests.
if (!connector_)
return;
// Connect to the MediaControllerManager and create a MediaController that
// controls the active session so we can observe it.
mojo::Remote<media_session::mojom::MediaControllerManager> controller_manager;
connector_->Connect(media_session::mojom::kServiceName,
controller_manager.BindNewPipeAndPassReceiver());
controller_manager->CreateActiveMediaController(
media_controller_.BindNewPipeAndPassReceiver());
// Observe the active media controller for changes to playback state and
// supported actions.
media_controller_->AddObserver(
media_controller_observer_receiver_.BindNewPipeAndPassRemote());
}
void MprisNotifier::MediaSessionInfoChanged(
media_session::mojom::MediaSessionInfoPtr session_info) {
DCHECK(service_);
session_info_ = std::move(session_info);
if (session_info_) {
if (session_info_->playback_state ==
media_session::mojom::MediaPlaybackState::kPlaying) {
service_->SetPlaybackStatus(
mpris::MprisService::PlaybackStatus::kPlaying);
} else {
service_->SetPlaybackStatus(mpris::MprisService::PlaybackStatus::kPaused);
}
} else {
service_->SetPlaybackStatus(mpris::MprisService::PlaybackStatus::kStopped);
}
}
void MprisNotifier::MediaSessionMetadataChanged(
const base::Optional<media_session::MediaMetadata>& metadata) {
if (metadata.has_value()) {
service_->SetTitle(metadata->title);
service_->SetArtist(metadata->artist);
service_->SetAlbum(metadata->album);
} else {
service_->SetTitle(base::string16());
service_->SetArtist(base::string16());
service_->SetAlbum(base::string16());
}
}
} // namespace content
// Copyright 2019 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 CONTENT_BROWSER_MEDIA_MPRIS_NOTIFIER_H_
#define CONTENT_BROWSER_MEDIA_MPRIS_NOTIFIER_H_
#include <memory>
#include <vector>
#include "content/common/content_export.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/media_session/public/mojom/media_controller.mojom.h"
namespace mpris {
class MprisService;
} // namespace mpris
namespace service_manager {
class Connector;
} // namespace service_manager
namespace content {
// The MprisNotifier connects to our MPRIS service and keeps it informed of the
// current media playstate and metadata. It observes changes to the active Media
// Session and updates MPRIS accordingly.
// TODO(https://crbug.com/949596): combine this with the
// NowPlayingInfoCenterNotifier (Mac) and SystemMediaControlsNotifier (Win) into
// something platform-independent.
class CONTENT_EXPORT MprisNotifier
: public media_session::mojom::MediaControllerObserver {
public:
explicit MprisNotifier(service_manager::Connector* connector);
~MprisNotifier() override;
void Initialize();
// media_session::mojom::MediaControllerObserver implementation.
void MediaSessionInfoChanged(
media_session::mojom::MediaSessionInfoPtr session_info) override;
void MediaSessionMetadataChanged(
const base::Optional<media_session::MediaMetadata>& metadata) override;
void MediaSessionActionsChanged(
const std::vector<media_session::mojom::MediaSessionAction>& actions)
override {}
void MediaSessionChanged(
const base::Optional<base::UnguessableToken>& request_id) override {}
void MediaSessionPositionChanged(
const base::Optional<media_session::MediaPosition>& position) override {}
void SetMprisServiceForTesting(mpris::MprisService* service) {
service_ = service;
}
private:
// Our connection to MPRIS.
mpris::MprisService* service_ = nullptr;
// Used to connect to the Media Session service.
service_manager::Connector* connector_;
// Tracks current media session state/metadata.
mojo::Remote<media_session::mojom::MediaController> media_controller_;
media_session::mojom::MediaSessionInfoPtr session_info_;
// Used to receive updates to the active media controller.
mojo::Receiver<media_session::mojom::MediaControllerObserver>
media_controller_observer_receiver_{this};
DISALLOW_COPY_AND_ASSIGN(MprisNotifier);
};
} // namespace content
#endif // CONTENT_BROWSER_MEDIA_MPRIS_NOTIFIER_H_
// Copyright 2019 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 "content/browser/media/mpris_notifier.h"
#include <memory>
#include <utility>
#include "base/strings/utf_string_conversions.h"
#include "services/media_session/public/mojom/media_session.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/mpris/mock_mpris_service.h"
namespace content {
using media_session::mojom::MediaPlaybackState;
using media_session::mojom::MediaSessionInfo;
using media_session::mojom::MediaSessionInfoPtr;
using testing::Expectation;
class MprisNotifierTest : public testing::Test {
public:
MprisNotifierTest() = default;
~MprisNotifierTest() override = default;
void SetUp() override {
notifier_ = std::make_unique<MprisNotifier>(/*connector=*/nullptr);
notifier_->SetMprisServiceForTesting(&mock_mpris_service_);
notifier_->Initialize();
}
protected:
void SimulatePlaying() {
MediaSessionInfoPtr session_info(MediaSessionInfo::New());
session_info->playback_state = MediaPlaybackState::kPlaying;
notifier_->MediaSessionInfoChanged(std::move(session_info));
}
void SimulatePaused() {
MediaSessionInfoPtr session_info(MediaSessionInfo::New());
session_info->playback_state = MediaPlaybackState::kPaused;
notifier_->MediaSessionInfoChanged(std::move(session_info));
}
void SimulateStopped() { notifier_->MediaSessionInfoChanged(nullptr); }
MprisNotifier& notifier() { return *notifier_; }
mpris::MockMprisService& mock_mpris_service() { return mock_mpris_service_; }
private:
std::unique_ptr<MprisNotifier> notifier_;
mpris::MockMprisService mock_mpris_service_;
DISALLOW_COPY_AND_ASSIGN(MprisNotifierTest);
};
TEST_F(MprisNotifierTest, ProperlyUpdatesPlaybackState) {
Expectation playing = EXPECT_CALL(
mock_mpris_service(),
SetPlaybackStatus(mpris::MprisService::PlaybackStatus::kPlaying));
Expectation paused =
EXPECT_CALL(
mock_mpris_service(),
SetPlaybackStatus(mpris::MprisService::PlaybackStatus::kPaused))
.After(playing);
EXPECT_CALL(mock_mpris_service(),
SetPlaybackStatus(mpris::MprisService::PlaybackStatus::kStopped))
.After(paused);
SimulatePlaying();
SimulatePaused();
SimulateStopped();
}
TEST_F(MprisNotifierTest, ProperlyUpdatesMetadata) {
EXPECT_CALL(mock_mpris_service(), SetTitle(base::ASCIIToUTF16("Foo")));
media_session::MediaMetadata metadata;
metadata.title = base::ASCIIToUTF16("Foo");
notifier().MediaSessionMetadataChanged(metadata);
}
} // namespace content
......@@ -18,7 +18,6 @@ import("//ppapi/buildflags/buildflags.gni")
import("//testing/test.gni")
import("//third_party/blink/public/public_features.gni")
import("//tools/v8_context_snapshot/v8_context_snapshot.gni")
import("//ui/base/mpris/buildflags/buildflags.gni")
import("//v8/gni/v8.gni")
if (is_android) {
......@@ -2290,11 +2289,6 @@ test("content_unittests") {
if (use_x11) {
deps += [ "//ui/gfx/x" ]
}
if (use_mpris) {
sources += [ "../browser/media/mpris_notifier_unittest.cc" ]
deps += [ "//ui/base/mpris:test_support" ]
}
}
if (enable_nocompile_tests) {
......
......@@ -3,6 +3,7 @@ include_rules = [
"+cc/base/math_util.h",
"+cc/paint",
"+chromeos/audio",
"+components/system_media_controls/linux/buildflags",
"+crypto",
"+device/udev_linux",
"+gpu",
......@@ -18,7 +19,6 @@ include_rules = [
"+third_party/libyuv",
"+third_party/opus",
"+third_party/skia",
"+ui/base/mpris/buildflags",
"+ui/display",
"+ui/events",
"+ui/gfx",
......
......@@ -323,11 +323,11 @@ jumbo_source_set("base") {
]
deps = [
"//base/allocator:buildflags",
"//components/system_media_controls/linux/buildflags",
"//gpu/command_buffer/common",
"//gpu/ipc/common:common",
"//third_party/libyuv",
"//third_party/widevine/cdm:headers",
"//ui/base/mpris/buildflags",
"//ui/display:display",
"//ui/events:events_base",
"//url:url",
......
......@@ -6,7 +6,7 @@
#include "base/command_line.h"
#include "build/build_config.h"
#include "ui/base/mpris/buildflags/buildflags.h"
#include "components/system_media_controls/linux/buildflags/buildflags.h"
namespace switches {
......
......@@ -10,9 +10,9 @@ import("//build/config/linux/pangocairo/pangocairo.gni")
import("//build/config/sanitizers/sanitizers.gni")
import("//build/config/ui.gni")
import("//build/util/branding.gni")
import("//components/system_media_controls/linux/buildflags/buildflags.gni")
import("//testing/test.gni")
import("//tools/grit/grit_rule.gni")
import("//ui/base/mpris/buildflags/buildflags.gni")
import("//ui/base/ui_features.gni")
import("//ui/ozone/ozone.gni")
......@@ -362,11 +362,7 @@ jumbo_component("base") {
"accelerators/media_keys_listener_win.cc",
]
} else if (use_mpris) {
sources += [
"accelerators/media_keys_listener_linux.cc",
"accelerators/mpris_media_keys_listener.cc",
"accelerators/mpris_media_keys_listener.h",
]
sources += [ "accelerators/media_keys_listener_linux.cc" ]
} else {
sources += [ "accelerators/media_keys_listener_stub.cc" ]
}
......@@ -468,13 +464,6 @@ jumbo_component("base") {
deps += [ "//components/system_media_controls" ]
if (use_mpris) {
deps += [
"//dbus",
"//ui/base/mpris",
]
}
if (use_x11 && use_aura) {
sources += [
"cursor/cursor_loader_x11.cc",
......@@ -1134,14 +1123,6 @@ test("ui_base_unittests") {
]
}
if (use_mpris) {
sources += [ "accelerators/mpris_media_keys_listener_unittest.cc" ]
deps += [
"//ui/base/mpris:test_support",
"//ui/base/mpris:unit_tests",
]
}
if (is_chromeos) {
deps += [ "//ui/events:dom_keycode_converter" ]
}
......
......@@ -4,7 +4,7 @@
#include "ui/base/accelerators/media_keys_listener.h"
#include "ui/base/accelerators/mpris_media_keys_listener.h"
#include "ui/base/accelerators/system_media_controls_media_keys_listener.h"
namespace ui {
......@@ -14,12 +14,17 @@ std::unique_ptr<MediaKeysListener> MediaKeysListener::Create(
DCHECK(delegate);
if (scope == Scope::kGlobal) {
if (!MprisMediaKeysListener::has_instance()) {
auto listener = std::make_unique<MprisMediaKeysListener>(delegate);
listener->Initialize();
if (!SystemMediaControlsMediaKeysListener::has_instance()) {
auto listener =
std::make_unique<SystemMediaControlsMediaKeysListener>(delegate);
bool success = listener->Initialize();
// The Linux implementation should always initialize successfully.
DCHECK(success);
return std::move(listener);
}
// We shouldn't try to create more than one MprisMediaKeysListener
// We shouldn't try to create more than one global MediaKeysListener
// instance.
NOTREACHED();
}
......
// Copyright 2019 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 "ui/base/accelerators/mpris_media_keys_listener.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/mpris/mpris_service.h"
namespace ui {
// static
bool MprisMediaKeysListener::has_instance_ = false;
MprisMediaKeysListener::MprisMediaKeysListener(
MediaKeysListener::Delegate* delegate)
: delegate_(delegate) {
DCHECK(delegate_);
DCHECK(!has_instance_);
has_instance_ = true;
}
MprisMediaKeysListener::~MprisMediaKeysListener() {
DCHECK(has_instance_);
has_instance_ = false;
}
void MprisMediaKeysListener::Initialize() {
// |service_| can be set for tests.
if (!service_)
service_ = mpris::MprisService::GetInstance();
DCHECK(service_);
service_->AddObserver(this);
}
bool MprisMediaKeysListener::StartWatchingMediaKey(KeyboardCode key_code) {
DCHECK(IsMediaKeycode(key_code));
key_codes_.insert(key_code);
DCHECK(service_);
switch (key_code) {
case VKEY_MEDIA_PLAY_PAUSE:
service_->SetCanPlay(true);
service_->SetCanPause(true);
break;
case VKEY_MEDIA_NEXT_TRACK:
service_->SetCanGoNext(true);
break;
case VKEY_MEDIA_PREV_TRACK:
service_->SetCanGoPrevious(true);
break;
case VKEY_MEDIA_STOP:
// No properties need to be changed.
break;
default:
NOTREACHED();
}
return true;
}
void MprisMediaKeysListener::StopWatchingMediaKey(KeyboardCode key_code) {
DCHECK(IsMediaKeycode(key_code));
key_codes_.erase(key_code);
DCHECK(service_);
switch (key_code) {
case VKEY_MEDIA_PLAY_PAUSE:
service_->SetCanPlay(false);
service_->SetCanPause(false);
break;
case VKEY_MEDIA_NEXT_TRACK:
service_->SetCanGoNext(false);
break;
case VKEY_MEDIA_PREV_TRACK:
service_->SetCanGoPrevious(false);
break;
case VKEY_MEDIA_STOP:
// No properties need to be changed.
break;
default:
NOTREACHED();
}
}
void MprisMediaKeysListener::SetIsMediaPlaying(bool is_playing) {
is_media_playing_ = is_playing;
}
void MprisMediaKeysListener::OnNext() {
MaybeSendKeyCode(VKEY_MEDIA_NEXT_TRACK);
}
void MprisMediaKeysListener::OnPrevious() {
MaybeSendKeyCode(VKEY_MEDIA_PREV_TRACK);
}
void MprisMediaKeysListener::OnPause() {
if (is_media_playing_)
MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE);
}
void MprisMediaKeysListener::OnPlayPause() {
MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE);
}
void MprisMediaKeysListener::OnStop() {
MaybeSendKeyCode(VKEY_MEDIA_STOP);
}
void MprisMediaKeysListener::OnPlay() {
if (!is_media_playing_)
MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE);
}
void MprisMediaKeysListener::MaybeSendKeyCode(KeyboardCode key_code) {
if (!key_codes_.contains(key_code))
return;
Accelerator accelerator(key_code, /*modifiers=*/0);
delegate_->OnMediaKeysAccelerator(accelerator);
}
} // namespace ui
// Copyright 2019 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 UI_BASE_ACCELERATORS_MPRIS_MEDIA_KEYS_LISTENER_H_
#define UI_BASE_ACCELERATORS_MPRIS_MEDIA_KEYS_LISTENER_H_
#include "base/containers/flat_set.h"
#include "ui/base/accelerators/media_keys_listener.h"
#include "ui/base/mpris/mpris_service_observer.h"
#include "ui/base/ui_base_export.h"
#include "ui/events/keycodes/keyboard_codes.h"
namespace mpris {
class MprisService;
} // namespace mpris
namespace ui {
// Implementation of MediaKeysListener that uses MprisService to globally listen
// for media key presses. It only allows for a single instance to be created in
// order to prevent conflicts from multiple listeners.
class UI_BASE_EXPORT MprisMediaKeysListener
: public MediaKeysListener,
public mpris::MprisServiceObserver {
public:
explicit MprisMediaKeysListener(MediaKeysListener::Delegate* delegate);
~MprisMediaKeysListener() override;
static bool has_instance() { return has_instance_; }
// Connects with the MprisService.
void Initialize();
// MediaKeysListener implementation.
bool StartWatchingMediaKey(KeyboardCode key_code) override;
void StopWatchingMediaKey(KeyboardCode key_code) override;
void SetIsMediaPlaying(bool is_playing) override;
// mpris::MprisServiceObserver implementation.
void OnNext() override;
void OnPrevious() override;
void OnPause() override;
void OnPlayPause() override;
void OnStop() override;
void OnPlay() override;
void SetMprisServiceForTesting(mpris::MprisService* service) {
service_ = service;
}
private:
static bool has_instance_;
// Sends the key code to the delegate if the delegate has asked for it.
void MaybeSendKeyCode(KeyboardCode key_code);
MediaKeysListener::Delegate* delegate_;
base::flat_set<KeyboardCode> key_codes_;
mpris::MprisService* service_ = nullptr;
bool is_media_playing_ = false;
DISALLOW_COPY_AND_ASSIGN(MprisMediaKeysListener);
};
} // namespace ui
#endif // UI_BASE_ACCELERATORS_MPRIS_MEDIA_KEYS_LISTENER_H_
// Copyright 2019 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 "ui/base/accelerators/mpris_media_keys_listener.h"
#include <memory>
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/mpris/mock_mpris_service.h"
using testing::_;
using testing::WithArg;
namespace ui {
namespace {
class MockMediaKeysListenerDelegate : public MediaKeysListener::Delegate {
public:
MockMediaKeysListenerDelegate() = default;
~MockMediaKeysListenerDelegate() override = default;
// MediaKeysListener::Delegate implementation.
MOCK_METHOD1(OnMediaKeysAccelerator, void(const Accelerator& accelerator));
private:
DISALLOW_COPY_AND_ASSIGN(MockMediaKeysListenerDelegate);
};
} // anonymous namespace
class MprisMediaKeysListenerTest : public testing::Test {
public:
MprisMediaKeysListenerTest() = default;
~MprisMediaKeysListenerTest() override = default;
void SetUp() override {
listener_ = std::make_unique<MprisMediaKeysListener>(&delegate_);
listener_->SetMprisServiceForTesting(&mock_mpris_service_);
}
protected:
mpris::MockMprisService& mock_mpris_service() { return mock_mpris_service_; }
MockMediaKeysListenerDelegate& delegate() { return delegate_; }
MprisMediaKeysListener* listener() { return listener_.get(); }
private:
mpris::MockMprisService mock_mpris_service_;
MockMediaKeysListenerDelegate delegate_;
std::unique_ptr<MprisMediaKeysListener> listener_;
DISALLOW_COPY_AND_ASSIGN(MprisMediaKeysListenerTest);
};
TEST_F(MprisMediaKeysListenerTest, ListensToMprisService) {
EXPECT_CALL(mock_mpris_service(), AddObserver(listener()));
listener()->Initialize();
}
TEST_F(MprisMediaKeysListenerTest, SimplePlayPauseTest) {
// Should be set to true when we start listening for the key.
EXPECT_CALL(mock_mpris_service(), SetCanPlay(true));
EXPECT_CALL(mock_mpris_service(), SetCanPause(true));
EXPECT_CALL(delegate(), OnMediaKeysAccelerator(_))
.WillOnce(WithArg<0>([](const Accelerator& accelerator) {
EXPECT_EQ(ui::VKEY_MEDIA_PLAY_PAUSE, accelerator.key_code());
}));
listener()->Initialize();
listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE);
// Simulate media key press.
listener()->OnPlayPause();
}
TEST_F(MprisMediaKeysListenerTest, KeyCanBeReRegistered) {
EXPECT_CALL(mock_mpris_service(), SetCanGoNext(true)).Times(2);
EXPECT_CALL(mock_mpris_service(), SetCanGoNext(false));
EXPECT_CALL(delegate(), OnMediaKeysAccelerator(_))
.WillOnce(WithArg<0>([](const Accelerator& accelerator) {
EXPECT_EQ(ui::VKEY_MEDIA_NEXT_TRACK, accelerator.key_code());
}));
listener()->Initialize();
// Start listening to register the key.
listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_NEXT_TRACK);
// Stop listening to unregister the key.
listener()->StopWatchingMediaKey(ui::VKEY_MEDIA_NEXT_TRACK);
// Start listening to re-register the key.
listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_NEXT_TRACK);
// Simulate media key press.
listener()->OnNext();
}
TEST_F(MprisMediaKeysListenerTest, ListenForMultipleKeys) {
// Should be set to true when we start listening for the key.
EXPECT_CALL(mock_mpris_service(), SetCanPlay(true));
EXPECT_CALL(mock_mpris_service(), SetCanPause(true));
EXPECT_CALL(mock_mpris_service(), SetCanGoPrevious(true));
// Should receive the key presses.
EXPECT_CALL(delegate(), OnMediaKeysAccelerator(_)).Times(2);
listener()->Initialize();
listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE);
listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_PREV_TRACK);
// Simulate media key press.
listener()->OnPlayPause();
listener()->OnPrevious();
}
TEST_F(MprisMediaKeysListenerTest, DoesNotFirePlayPauseOnPauseEventWhenPaused) {
// Should be set to true when we start listening for the key.
EXPECT_CALL(mock_mpris_service(), SetCanPlay(true));
EXPECT_CALL(mock_mpris_service(), SetCanPause(true));
EXPECT_CALL(delegate(), OnMediaKeysAccelerator(_)).Times(0);
listener()->Initialize();
listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE);
listener()->SetIsMediaPlaying(false);
// Simulate media key press.
listener()->OnPause();
}
TEST_F(MprisMediaKeysListenerTest, DoesNotFirePlayPauseOnPlayEventWhenPlaying) {
// Should be set to true when we start listening for the key.
EXPECT_CALL(mock_mpris_service(), SetCanPlay(true));
EXPECT_CALL(mock_mpris_service(), SetCanPause(true));
EXPECT_CALL(delegate(), OnMediaKeysAccelerator(_)).Times(0);
listener()->Initialize();
listener()->StartWatchingMediaKey(ui::VKEY_MEDIA_PLAY_PAUSE);
listener()->SetIsMediaPlaying(true);
// Simulate media key press.
listener()->OnPlay();
}
} // namespace ui
......@@ -116,18 +116,22 @@ void SystemMediaControlsMediaKeysListener::OnPrevious() {
MaybeSendKeyCode(VKEY_MEDIA_PREV_TRACK);
}
void SystemMediaControlsMediaKeysListener::OnPlay() {
if (!is_media_playing_)
MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE);
}
void SystemMediaControlsMediaKeysListener::OnPause() {
if (is_media_playing_)
MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE);
}
void SystemMediaControlsMediaKeysListener::OnStop() {
MaybeSendKeyCode(VKEY_MEDIA_STOP);
void SystemMediaControlsMediaKeysListener::OnPlayPause() {
MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE);
}
void SystemMediaControlsMediaKeysListener::OnPlay() {
if (!is_media_playing_)
MaybeSendKeyCode(VKEY_MEDIA_PLAY_PAUSE);
void SystemMediaControlsMediaKeysListener::OnStop() {
MaybeSendKeyCode(VKEY_MEDIA_STOP);
}
void SystemMediaControlsMediaKeysListener::MaybeSendKeyCode(
......
......@@ -38,11 +38,13 @@ class UI_BASE_EXPORT SystemMediaControlsMediaKeysListener
void SetIsMediaPlaying(bool is_playing) override;
// system_media_controls::SystemMediaControlsObserver implementation.
void OnServiceReady() override {}
void OnNext() override;
void OnPrevious() override;
void OnPlay() override;
void OnPause() override;
void OnPlayPause() override;
void OnStop() override;
void OnPlay() override;
void SetSystemMediaControlsForTesting(
system_media_controls::SystemMediaControls* service) {
......
# Copyright 2019 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.
component("mpris") {
sources = [
"mpris_service.cc",
"mpris_service.h",
"mpris_service_impl.cc",
"mpris_service_impl.h",
"mpris_service_observer.h",
]
defines = [ "IS_MPRIS_IMPL" ]
deps = [
"//base",
"//build:branding_buildflags",
"//components/dbus/properties",
"//components/dbus/thread_linux",
"//dbus",
]
}
source_set("unit_tests") {
testonly = true
sources = [
"mpris_service_impl_unittest.cc",
]
deps = [
":mpris",
"//base",
"//base/test:test_support",
"//components/dbus/thread_linux",
"//dbus",
"//dbus:test_support",
"//testing/gmock",
"//testing/gtest",
]
}
static_library("test_support") {
testonly = true
sources = [
"mock_mpris_service.cc",
"mock_mpris_service.h",
]
deps = [
":mpris",
"//base",
"//testing/gmock",
]
}
include_rules = [
"+components/dbus",
"+dbus",
]
// Copyright 2019 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 "ui/base/mpris/mock_mpris_service.h"
namespace mpris {
MockMprisService::MockMprisService() = default;
MockMprisService::~MockMprisService() = default;
} // namespace mpris
// Copyright 2019 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 UI_BASE_MPRIS_MOCK_MPRIS_SERVICE_H_
#define UI_BASE_MPRIS_MOCK_MPRIS_SERVICE_H_
#include <string>
#include "base/macros.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "ui/base/mpris/mpris_service.h"
namespace mpris {
class MprisServiceObserver;
// Mock implementation of MprisService for testing.
class MockMprisService : public MprisService {
public:
MockMprisService();
~MockMprisService() override;
// MprisService implementation.
MOCK_METHOD0(StartService, void());
MOCK_METHOD1(AddObserver, void(MprisServiceObserver* observer));
MOCK_METHOD1(RemoveObserver, void(MprisServiceObserver* observer));
MOCK_METHOD1(SetCanGoNext, void(bool value));
MOCK_METHOD1(SetCanGoPrevious, void(bool value));
MOCK_METHOD1(SetCanPlay, void(bool value));
MOCK_METHOD1(SetCanPause, void(bool value));
MOCK_METHOD1(SetPlaybackStatus, void(PlaybackStatus value));
MOCK_METHOD1(SetTitle, void(const base::string16& value));
MOCK_METHOD1(SetArtist, void(const base::string16& value));
MOCK_METHOD1(SetAlbum, void(const base::string16& value));
MOCK_CONST_METHOD0(GetServiceName, std::string());
private:
DISALLOW_COPY_AND_ASSIGN(MockMprisService);
};
} // namespace mpris
#endif // UI_BASE_MPRIS_MOCK_MPRIS_SERVICE_H_
// Copyright 2019 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 "ui/base/mpris/mpris_service.h"
#include "build/branding_buildflags.h"
#include "ui/base/mpris/mpris_service_impl.h"
namespace mpris {
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
const char kMprisAPIServiceNamePrefix[] =
"org.mpris.MediaPlayer2.chrome.instance";
#else
const char kMprisAPIServiceNamePrefix[] =
"org.mpris.MediaPlayer2.chromium.instance";
#endif
const char kMprisAPIObjectPath[] = "/org/mpris/MediaPlayer2";
const char kMprisAPIInterfaceName[] = "org.mpris.MediaPlayer2";
const char kMprisAPIPlayerInterfaceName[] = "org.mpris.MediaPlayer2.Player";
// static
MprisService* MprisService::GetInstance() {
return MprisServiceImpl::GetInstance();
}
MprisService::~MprisService() = default;
} // namespace mpris
// Copyright 2019 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 UI_BASE_MPRIS_MPRIS_SERVICE_H_
#define UI_BASE_MPRIS_MPRIS_SERVICE_H_
#include <string>
#include "base/component_export.h"
#include "base/strings/string16.h"
namespace mpris {
class MprisServiceObserver;
COMPONENT_EXPORT(MPRIS) extern const char kMprisAPIServiceNamePrefix[];
COMPONENT_EXPORT(MPRIS) extern const char kMprisAPIObjectPath[];
COMPONENT_EXPORT(MPRIS) extern const char kMprisAPIInterfaceName[];
COMPONENT_EXPORT(MPRIS) extern const char kMprisAPIPlayerInterfaceName[];
// A D-Bus service conforming to the MPRIS spec:
// https://specifications.freedesktop.org/mpris-spec/latest/
class COMPONENT_EXPORT(MPRIS) MprisService {
public:
enum class PlaybackStatus {
kPlaying,
kPaused,
kStopped,
};
// Returns the singleton instance, creating if necessary.
static MprisService* GetInstance();
// Starts the DBus service.
virtual void StartService() = 0;
virtual void AddObserver(MprisServiceObserver* observer) = 0;
virtual void RemoveObserver(MprisServiceObserver* observer) = 0;
// Setters for properties.
virtual void SetCanGoNext(bool value) = 0;
virtual void SetCanGoPrevious(bool value) = 0;
virtual void SetCanPlay(bool value) = 0;
virtual void SetCanPause(bool value) = 0;
virtual void SetPlaybackStatus(PlaybackStatus value) = 0;
virtual void SetTitle(const base::string16& value) = 0;
virtual void SetArtist(const base::string16& value) = 0;
virtual void SetAlbum(const base::string16& value) = 0;
// Returns the generated service name.
virtual std::string GetServiceName() const = 0;
protected:
virtual ~MprisService();
};
} // namespace mpris
#endif // UI_BASE_MPRIS_MPRIS_SERVICE_H_
// Copyright 2019 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 UI_BASE_MPRIS_MPRIS_SERVICE_OBSERVER_H_
#define UI_BASE_MPRIS_MPRIS_SERVICE_OBSERVER_H_
#include "base/component_export.h"
#include "base/observer_list_types.h"
namespace mpris {
// Interface to observe events on the MprisService.
class COMPONENT_EXPORT(MPRIS) MprisServiceObserver
: public base::CheckedObserver {
public:
// Called when the service has completed setting up.
virtual void OnServiceReady() {}
// Called when the associated method from the org.mpris.MediaPlayer2.Player
// interface is called.
virtual void OnNext() {}
virtual void OnPrevious() {}
virtual void OnPause() {}
virtual void OnPlayPause() {}
virtual void OnStop() {}
virtual void OnPlay() {}
};
} // namespace mpris
#endif // UI_BASE_MPRIS_MPRIS_SERVICE_OBSERVER_H_
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