2
* Copyright © 2014 Canonical Ltd.
4
* This program is free software: you can redistribute it and/or modify it
5
* under the terms of the GNU Lesser General Public License version 3,
6
* as published by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU Lesser General Public License for more details.
13
* You should have received a copy of the GNU Lesser General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16
* Authored by: Thomas Voß <thomas.voss@canonical.com>
19
#include <core/media/power/state_controller.h>
21
#include <core/dbus/macros.h>
22
#include <core/dbus/object.h>
26
namespace media = core::ubuntu::media;
28
namespace com { namespace canonical {
33
static const std::string& name()
35
static std::string s = "com.canonical.Unity.Screen";
39
static const core::dbus::types::ObjectPath& path()
41
static core::dbus::types::ObjectPath p{"/com/canonical/Unity/Screen"};
45
DBUS_CPP_METHOD_DEF(keepDisplayOn, Screen)
46
DBUS_CPP_METHOD_DEF(removeDisplayOnRequest, Screen)
52
static std::string& name()
54
static std::string s = "com.canonical.powerd";
58
static const core::dbus::types::ObjectPath& path()
60
static core::dbus::types::ObjectPath p{"/com/canonical/powerd"};
64
DBUS_CPP_METHOD_DEF(requestSysState, com::canonical::powerd::Interface)
65
DBUS_CPP_METHOD_DEF(clearSysState, com::canonical::powerd::Interface)
73
struct DisplayStateLock : public media::power::StateController::Lock<media::power::DisplayState>,
74
public std::enable_shared_from_this<DisplayStateLock>
76
// To safe us some typing
77
typedef std::shared_ptr<DisplayStateLock> Ptr;
79
// We postpone releasing the display for this amount of time.
80
static boost::posix_time::seconds timeout_for_release()
82
return boost::posix_time::seconds{4};
85
// The invalid cookie marker.
86
static constexpr const std::int32_t the_invalid_cookie{-1};
88
DisplayStateLock(const media::power::StateController::Ptr& parent,
89
boost::asio::io_service& io_service,
90
const core::dbus::Object::Ptr& object)
94
cookie{the_invalid_cookie}
98
// From core::ubuntu::media::power::StateController::Lock<DisplayState>
99
void request_acquire(media::power::DisplayState state) override
101
if (state == media::power::DisplayState::off)
104
std::weak_ptr<DisplayStateLock> wp{shared_from_this()};
106
object->invoke_method_asynchronously_with_callback<com::canonical::Unity::Screen::keepDisplayOn, std::int32_t>(
107
[wp, state](const core::dbus::Result<std::int32_t>& result)
109
if (result.is_error())
111
std::cerr << result.error().print() << std::endl;
115
if (auto sp = wp.lock())
117
sp->cookie = result.value();
118
sp->signals.acquired(state);
123
void request_release(media::power::DisplayState state) override
125
if (state == media::power::DisplayState::off)
128
if (cookie == the_invalid_cookie)
131
// We make sure that we keep ourselves alive to make sure
132
// that release requests are always correctly issued.
133
auto sp = shared_from_this();
135
auto current_cookie(cookie);
137
timeout.expires_from_now(timeout_for_release());
138
timeout.async_wait([sp, state, current_cookie](const boost::system::error_code& ec)
140
// We only return early from the timeout handler if the operation has been
141
// explicitly aborted before.
142
if (ec == boost::asio::error::operation_aborted)
145
sp->object->invoke_method_asynchronously_with_callback<com::canonical::Unity::Screen::removeDisplayOnRequest, void>(
146
[sp, state, current_cookie](const core::dbus::Result<void>& result)
148
if (result.is_error())
150
std::cerr << result.error().print() << std::endl;
154
sp->signals.released(state);
156
// We might have issued a different request before and
157
// only call the display state done if the original cookie
158
// corresponds to the one we just gave up.
159
if (sp->cookie == current_cookie)
160
sp->cookie = the_invalid_cookie;
166
// Emitted whenever the acquire request completes.
167
const core::Signal<media::power::DisplayState>& acquired() const override
169
return signals.acquired;
172
// Emitted whenever the release request completes.
173
const core::Signal<media::power::DisplayState>& released() const override
175
return signals.released;
178
media::power::StateController::Ptr parent;
179
boost::asio::deadline_timer timeout;
180
core::dbus::Object::Ptr object;
185
core::Signal<media::power::DisplayState> acquired;
186
core::Signal<media::power::DisplayState> released;
190
struct SystemStateLock : public media::power::StateController::Lock<media::power::SystemState>,
191
public std::enable_shared_from_this<SystemStateLock>
193
static constexpr const char* wake_lock_name
195
"media-hub-playback_lock"
198
SystemStateLock(const media::power::StateController::Ptr& parent, const core::dbus::Object::Ptr& object)
204
// Informs the system that the caller would like
205
// the system to stay active.
206
void request_acquire(media::power::SystemState state) override
208
if (state == media::power::SystemState::suspend)
211
// Keep scope of this lock tight as to avoid
212
// deadlocks on PlayerImplementation destruction
214
std::lock_guard<std::mutex> lg{system_state_cookie_store_guard};
215
if (system_state_cookie_store.count(state) > 0)
219
std::weak_ptr<SystemStateLock> wp{shared_from_this()};
221
object->invoke_method_asynchronously_with_callback<com::canonical::powerd::Interface::requestSysState, std::string>([wp, state](const core::dbus::Result<std::string>& result)
223
if (result.is_error()) // TODO(tvoss): We should log the error condition here.
226
if (auto sp = wp.lock())
228
std::lock_guard<std::mutex> lg{sp->system_state_cookie_store_guard};
230
sp->system_state_cookie_store[state] = result.value();
231
sp->signals.acquired(state);
233
}, std::string{wake_lock_name}, static_cast<std::int32_t>(state));
236
// Informs the system that the caller does not
237
// require the system to stay active anymore.
238
void request_release(media::power::SystemState state) override
240
if (state == media::power::SystemState::suspend)
243
std::lock_guard<std::mutex> lg{system_state_cookie_store_guard};
245
if (system_state_cookie_store.count(state) == 0)
248
std::weak_ptr<SystemStateLock> wp{shared_from_this()};
250
object->invoke_method_asynchronously_with_callback<com::canonical::powerd::Interface::clearSysState, void>([wp, state](const core::dbus::Result<void>& result)
252
if (result.is_error())
253
std::cerr << result.error().print() << std::endl;
255
if (auto sp = wp.lock())
257
std::lock_guard<std::mutex> lg{sp->system_state_cookie_store_guard};
259
sp->system_state_cookie_store.erase(state);
260
sp->signals.released(state);
262
}, system_state_cookie_store.at(state));
265
// Emitted whenever the acquire request completes.
266
const core::Signal<media::power::SystemState>& acquired() const override
268
return signals.acquired;
271
// Emitted whenever the release request completes.
272
const core::Signal<media::power::SystemState>& released() const override
274
return signals.released;
277
// Guards concurrent accesses to the cookie store.
278
std::mutex system_state_cookie_store_guard;
279
// Maps previously requested system states to the cookies returned
280
// by the remote end. Used for keeping track of acquired states and
281
// associated cookies to be able to release previously granted acquisitions.
282
std::map<media::power::SystemState, std::string> system_state_cookie_store;
283
media::power::StateController::Ptr parent;
284
core::dbus::Object::Ptr object;
287
core::Signal<media::power::SystemState> acquired;
288
core::Signal<media::power::SystemState> released;
292
struct StateController : public media::power::StateController,
293
public std::enable_shared_from_this<impl::StateController>
295
StateController(media::helper::ExternalServices& es)
296
: external_services{es},
299
core::dbus::Service::use_service<com::canonical::powerd::Interface>(external_services.system)
300
->object_for_path(com::canonical::powerd::Interface::path())
304
core::dbus::Service::use_service<com::canonical::Unity::Screen>(external_services.system)
305
->object_for_path(com::canonical::Unity::Screen::path())
310
media::power::StateController::Lock<media::power::SystemState>::Ptr system_state_lock() override
312
return std::make_shared<impl::SystemStateLock>(shared_from_this(), powerd);
315
media::power::StateController::Lock<media::power::DisplayState>::Ptr display_state_lock() override
317
return std::make_shared<impl::DisplayStateLock>(shared_from_this(), external_services.io_service, unity_screen);
320
media::helper::ExternalServices& external_services;
321
core::dbus::Object::Ptr powerd;
322
core::dbus::Object::Ptr unity_screen;
327
media::power::StateController::Ptr media::power::make_platform_default_state_controller(core::ubuntu::media::helper::ExternalServices& external_services)
329
return std::make_shared<impl::StateController>(external_services);
332
// operator<< pretty prints the given display state to the given output stream.
333
std::ostream& media::power::operator<<(std::ostream& out, media::power::DisplayState state)
337
case media::power::DisplayState::off:
338
return out << "DisplayState::off";
339
case media::power::DisplayState::on:
340
return out << "DisplayState::on";
346
// operator<< pretty prints the given system state to the given output stream.
347
std::ostream& media::power::operator<<(std::ostream& out, media::power::SystemState state)
351
case media::power::SystemState::active:
352
return out << "SystemState::active";
353
case media::power::SystemState::blank_on_proximity:
354
return out << "SystemState::blank_on_proximity";
355
case media::power::SystemState::suspend:
356
return out << "SystemState::suspend";