Music Hub  ..
A session-wide music playback service
state_controller.cpp
Go to the documentation of this file.
1 /*
2  * Copyright © 2014 Canonical Ltd.
3  * Copyright © 2022 UBports Foundation.
4  *
5  * Contact: Alberto Mardegan <mardy@users.sourceforge.net>
6  *
7  * This program is free software: you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License version 3,
9  * as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program. If not, see <http://www.gnu.org/licenses/>.
18  *
19  * Authored by: Thomas Voß <thomas.voss@canonical.com>
20  */
21 
22 #include "power/state_controller.h"
23 
24 #include "logging.h"
25 
26 #include <QDBusInterface>
27 #include <QDBusPendingCall>
28 #include <QDBusPendingCallWatcher>
29 #include <QDBusPendingReply>
30 #include <QTimer>
31 #include <QWeakPointer>
32 
33 #include <functional>
34 
35 // We allow the tests to reconfigure this value
36 #ifndef DISPLAY_RELEASE_INTERVAL
37 #define DISPLAY_RELEASE_INTERVAL 4000
38 #endif
39 
40 using namespace lomiri::MediaHubService::power;
41 
42 namespace media = lomiri::MediaHubService;
43 
44 namespace lomiri {
45 namespace MediaHubService {
46 namespace power {
47 
48 uint qHash(SystemState state, uint seed) {
49  return ::qHash(static_cast<uint>(state), seed);
50 }
51 
53 public:
55  m_interface(QStringLiteral("com.canonical.Unity.Screen"),
56  QStringLiteral("/com/canonical/Unity/Screen"),
57  QStringLiteral("com.canonical.Unity.Screen"),
58  QDBusConnection::systemBus()),
59  m_requestId(-1)
60  {
61  }
62 
63  using Callback = std::function<void(void)>;
64 
65  void requestDisplayOn(const Callback &cb) {
66  if (m_requestId >= 0) {
67  MH_ERROR("Display ON was already requested!");
68  return;
69  }
70 
71  QDBusPendingCall call = m_interface.asyncCall("keepDisplayOn");
72  auto watcher = new QDBusPendingCallWatcher(call);
73  QObject::connect(watcher, &QDBusPendingCallWatcher::finished,
74  [this, cb](QDBusPendingCallWatcher *watcher) {
75  QDBusPendingReply<int32_t> reply = *watcher;
76  if (reply.isError()) {
77  MH_ERROR() << "Error requesting display ON:" << reply.error().message();
78  } else {
79  m_requestId = reply.value();
80  cb();
81  }
82  watcher->deleteLater();
83  });
84  }
85 
86  void releaseDisplayOn(const Callback &cb) {
87  if (m_requestId < 0) {
88  MH_WARNING("Display ON was not requested!");
89  return;
90  }
91 
92  QDBusPendingCall call = m_interface.asyncCall("removeDisplayOnRequest", m_requestId);
93  auto watcher = new QDBusPendingCallWatcher(call);
94  QObject::connect(watcher, &QDBusPendingCallWatcher::finished,
95  [this, cb](QDBusPendingCallWatcher *watcher) {
96  QDBusPendingReply<void> reply = *watcher;
97  if (reply.isError()) {
98  MH_ERROR() << "Error releasing display ON:" << reply.error().message();
99  } else {
100  m_requestId = -1;
101  cb();
102  }
103  watcher->deleteLater();
104  });
105  }
106 
107 private:
108  QDBusInterface m_interface;
109  int32_t m_requestId;
110 };
111 
113 public:
115  m_interface(QStringLiteral("com.lomiri.Repowerd"),
116  QStringLiteral("/com/lomiri/Repowerd"),
117  QStringLiteral("com.lomiri.Repowerd"),
118  QDBusConnection::systemBus())
119  {
120  }
121 
122  using Callback = std::function<void(SystemState state)>;
123 
125  const Callback &cb)
126  {
127  MH_TRACE("");
128 
129  if (state == media::power::SystemState::suspend) {
130  return;
131  }
132 
133  QDBusPendingCall call =
134  m_interface.asyncCall("requestSysState",
135  QStringLiteral("media-hub-playback_lock"),
136  static_cast<int32_t>(state));
137  auto watcher = new QDBusPendingCallWatcher(call);
138  QObject::connect(watcher, &QDBusPendingCallWatcher::finished,
139  [this, state, cb](QDBusPendingCallWatcher *watcher) {
140  QDBusPendingReply<QString> reply = *watcher;
141  if (reply.isError()) {
142  MH_ERROR() << "Error requesting system state:" << reply.error().message();
143  } else {
144  m_cookieStore.insert(state, reply.value());
145  cb(state);
146  }
147  watcher->deleteLater();
148  });
149  }
150 
152  const Callback &cb)
153  {
154  if (state == media::power::SystemState::suspend) {
155  return;
156  }
157  const auto i = m_cookieStore.find(state);
158  if (i == m_cookieStore.end()) {
159  return; // state was never requested
160  }
161 
162  QDBusPendingCall call = m_interface.asyncCall("clearSysState", i.value());
163  auto watcher = new QDBusPendingCallWatcher(call);
164  QObject::connect(watcher, &QDBusPendingCallWatcher::finished,
165  [this, state, cb](QDBusPendingCallWatcher *watcher) {
166  QDBusPendingReply<void> reply = *watcher;
167  if (reply.isError()) {
168  MH_ERROR() << "Error releasing system state:" << reply.error().message();
169  } else {
170  m_cookieStore.remove(state);
171  cb(state);
172  }
173  watcher->deleteLater();
174  });
175  }
176 
177 private:
178  QDBusInterface m_interface;
179  QHash<SystemState, QString> m_cookieStore;
180 };
181 
183 public:
185 
186 private:
187  friend class StateController;
188  DisplayInterface m_display;
189  int m_displayLockCount = 0;
190  SystemStateInterface m_system;
191  int m_systemLockCount = 0;
192  QTimer m_displayReleaseTimer;
193 };
194 
196 {
198 };
199 
200 }}} // namespace
201 
203 {
204  m_displayReleaseTimer.setSingleShot(true);
205  m_displayReleaseTimer.setTimerType(Qt::VeryCoarseTimer);
206  m_displayReleaseTimer.setInterval(DISPLAY_RELEASE_INTERVAL);
207  m_displayReleaseTimer.callOnTimeout(q, [this, q]() {
208  auto emitReleaseSignal = [q]() {
209  Q_EMIT q->displayOnReleased();
210  };
211  m_display.releaseDisplayOn(emitReleaseSignal);
212  });
213 }
214 
216  QObject(),
217  d_ptr(new StateControllerPrivate(this))
218 {
219 }
220 
222 
223 QSharedPointer<StateController> StateController::instance()
224 {
225  static QWeakPointer<CreatableStateController> weakRef;
226 
227  QSharedPointer<CreatableStateController> strong = weakRef.toStrongRef();
228  if (!strong) {
229  strong = QSharedPointer<CreatableStateController>::create();
230  weakRef = strong;
231  }
232  return strong;
233 }
234 
236 {
237  Q_D(StateController);
238  if (++d->m_displayLockCount == 1) {
239  MH_INFO("Requesting new display wakelock.");
240  d->m_display.requestDisplayOn([this]() {
241  Q_EMIT displayOnAcquired();
242  });
243  }
244 }
245 
247 {
248  Q_D(StateController);
249  if (--d->m_displayLockCount == 0) {
250  MH_INFO("Clearing display wakelock.");
251  d->m_displayReleaseTimer.start();
252  }
253 }
254 
256 {
257  Q_D(StateController);
258  if (++d->m_systemLockCount == 1) {
259  MH_INFO("Requesting new system wakelock.");
260  d->m_system.requestSystemState(state, [this](SystemState state) {
261  Q_EMIT systemStateAcquired(state);
262  });
263  }
264 }
265 
267 {
268  Q_D(StateController);
269  if (--d->m_systemLockCount == 0) {
270  MH_INFO("Clearing system wakelock.");
271  d->m_system.releaseSystemState(state, [this](SystemState state) {
272  Q_EMIT systemStateReleased(state);
273  });
274  }
275 }
lomiri::MediaHubService::power::DisplayInterface::releaseDisplayOn
void releaseDisplayOn(const Callback &cb)
Definition: state_controller.cpp:86
QObject
lomiri::MediaHubService::power::StateControllerPrivate
Definition: state_controller.cpp:182
lomiri::MediaHubService::power::SystemStateInterface::SystemStateInterface
SystemStateInterface()
Definition: state_controller.cpp:114
lomiri::MediaHubService::power::StateController::systemStateReleased
void systemStateReleased(SystemState state)
lomiri::MediaHubService::power::SystemStateInterface
Definition: state_controller.cpp:112
lomiri::MediaHubService::power::SystemStateInterface::releaseSystemState
void releaseSystemState(media::power::SystemState state, const Callback &cb)
Definition: state_controller.cpp:151
lomiri::MediaHubService::power::SystemStateInterface::requestSystemState
void requestSystemState(SystemState state, const Callback &cb)
Definition: state_controller.cpp:124
lomiri::MediaHubService::power::StateController
Definition: state_controller.h:51
lomiri::MediaHubService::power::StateControllerPrivate::StateControllerPrivate
StateControllerPrivate(StateController *q)
Definition: state_controller.cpp:202
lomiri::MediaHubService::power::StateController::displayOnAcquired
void displayOnAcquired()
lomiri::MediaHubService::power::DisplayInterface
Definition: state_controller.cpp:52
state_controller.h
lomiri::MediaHubService::power::DisplayInterface::DisplayInterface
DisplayInterface()
Definition: state_controller.cpp:54
lomiri::MediaHubService::power::qHash
uint qHash(SystemState state, uint seed)
Definition: state_controller.cpp:48
lomiri::MediaHubService::power::StateController::requestDisplayOn
void requestDisplayOn()
Definition: state_controller.cpp:235
lomiri::MediaHubService::power::StateController::releaseDisplayOn
void releaseDisplayOn()
Definition: state_controller.cpp:246
MH_ERROR
#define MH_ERROR(...)
Definition: logging.h:41
lomiri::MediaHubService::power::DisplayInterface::Callback
std::function< void(void)> Callback
Definition: state_controller.cpp:63
lomiri::MediaHubService::power::DisplayInterface::requestDisplayOn
void requestDisplayOn(const Callback &cb)
Definition: state_controller.cpp:65
lomiri::MediaHubService::power::StateController::instance
static QSharedPointer< StateController > instance()
Definition: state_controller.cpp:223
MH_TRACE
#define MH_TRACE(...)
Definition: logging.h:37
lomiri::MediaHubService
Definition: context.h:28
lomiri::MediaHubService::power::StateController::~StateController
~StateController()
lomiri::MediaHubService::power::SystemState
SystemState
Definition: state_controller.h:37
lomiri::MediaHubService::power::SystemStateInterface::Callback
std::function< void(SystemState state)> Callback
Definition: state_controller.cpp:122
lomiri::MediaHubService::power::StateController::releaseSystemState
void releaseSystemState(SystemState state)
Definition: state_controller.cpp:266
lomiri::MediaHubService::power
Definition: battery_observer.cpp:35
DISPLAY_RELEASE_INTERVAL
#define DISPLAY_RELEASE_INTERVAL
Definition: state_controller.cpp:37
MH_INFO
#define MH_INFO(...)
Definition: logging.h:39
lomiri::MediaHubService::power::StateController::requestSystemState
void requestSystemState(SystemState state)
Definition: state_controller.cpp:255
lomiri::MediaHubService::power::CreatableStateController
Definition: state_controller.cpp:195
lomiri::MediaHubService::power::StateController::displayOnReleased
void displayOnReleased()
lomiri::MediaHubService::power::StateController::StateController
StateController()
Definition: state_controller.cpp:215
lomiri
Definition: dbus_utils.h:24
lomiri::MediaHubService::power::StateController::systemStateAcquired
void systemStateAcquired(SystemState state)
MH_WARNING
#define MH_WARNING(...)
Definition: logging.h:40