Merge lp:~thomas-voss/media-hub/introduce-power-controller-interface into lp:media-hub
- introduce-power-controller-interface
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Ricardo Mendoza |
Approved revision: | 119 |
Merged at revision: | 119 |
Proposed branch: | lp:~thomas-voss/media-hub/introduce-power-controller-interface |
Merge into: | lp:media-hub |
Prerequisite: | lp:~thomas-voss/media-hub/move-playbin-implementation-to-cpp-file |
Diff against target: |
1357 lines (+781/-284) 12 files modified
src/core/media/CMakeLists.txt (+4/-0) src/core/media/external_services.h (+83/-0) src/core/media/player_implementation.cpp (+50/-66) src/core/media/player_implementation.h (+18/-6) src/core/media/power/state_controller.cpp (+360/-0) src/core/media/power/state_controller.h (+108/-0) src/core/media/powerd_service.h (+0/-73) src/core/media/server/server.cpp (+121/-8) src/core/media/service_implementation.cpp (+28/-56) src/core/media/service_implementation.h (+8/-2) src/core/media/unity_screen_service.h (+0/-72) tests/CMakeLists.txt (+1/-1) |
To merge this branch: | bzr merge lp:~thomas-voss/media-hub/introduce-power-controller-interface |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Approve | |
Jim Hodapp (community) | code | Needs Fixing | |
Review via email:
|
Commit message
Introduce a common class media::
* Access the system and session bus instances.
* Prepares for integration testing scenarios as we can switch to private testing bus instances.
* Dispatch execution of tasks to worker threads.
* Requires only one external worker thread transparently shared by implementations requiring access to the respective bus instances.
Introduce interfaces media::
* The display subsystem.
* The overall system power state.
Provide two implementations talking to the com.canonical.
that implement media::
Adjust existing implementation to leverage power::
Adjust server setup to:
* hand down an instance of media::
* spin up two threads running the actual service and the external service helper in an exception-safe way.
Disable compilation of acceptance tests until the end of the wave of merge proposals to avoid having to resync. All of them are disabled anyway.
Description of the change
Introduce a common class media::
* Access the system and session bus instances.
* Prepares for integration testing scenarios as we can switch to private testing bus instances.
* Dispatch execution of tasks to worker threads.
* Requires only one external worker thread transparently shared by implementations requiring access to the respective bus instances.
Introduce interfaces media::
* The display subsystem.
* The overall system power state.
Provide two implementations talking to the com.canonical.
that implement media::
Adjust existing implementation to leverage power::
Adjust server setup to:
* hand down an instance of media::
* spin up two threads running the actual service and the external service helper in an exception-safe way.
Disable compilation of acceptance tests until the end of the wave of merge proposals to avoid having to resync. All of them are disabled anyway.
- 105. By Thomas Voß
-
Initialize media::
RecorderObserve r in the ctor's initializer list.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
- 106. By Thomas Voß
-
Remerge prereq branch.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:105
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:106
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Jim Hodapp (jhodapp) wrote : | # |
There's a lot to this one and we'll want to test the wakelock parts extremely well since there have been issues in the past with race conditions. Looks good, several comments inline below:
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Thomas Voß (thomas-voss) : | # |
- 107. By Thomas Voß
-
[ Jim Hodapp ]
* Resubmitting with prerequisite branch (LP: #1331041)
[ Justin McPherson ]
* Resubmitting with prerequisite branch (LP: #1331041) - 108. By Thomas Voß
-
Address review comments.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:108
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 109. By Thomas Voß
-
Fix ftbfs.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:109
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 110. By Thomas Voß
-
[ Jim Hodapp ]
* Error reporting all the way up to the app level from the playbin
pipeline.
[ Ubuntu daily release ]
* New rebuild forced
[ Jim Hodapp ]
* Don't auto-resume playback of videos after a phone call ends. (LP:
#1411273)
[ Ubuntu daily release ]
* New rebuild forced
[ Ricardo Salveti de Araujo ]
* service_implementation: adding debug for call started/ended signals.
Make sure account and connection are available when setting up
account manager (patch from Gustavo Boiko). call_monitor: don't
check caps when hooking up on/off signals, until bug 1409125 is
fixed. Enable parallel building . (LP: #1409125)
[ Jim Hodapp ]
* Pause playback when recording begins. (LP: #1398047)
[ Ricardo Salveti de Araujo ]
* call_monitor.cpp: waiting for bridge to be up, and also protecting
the on_change call (LP: #1408137)
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:110
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 111. By Thomas Voß
-
Merge prereq branch.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:111
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 112. By Thomas Voß
-
Fix init issue for assigning executors to buses.
- 113. By Thomas Voß
-
Merge prereq branch.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:113
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 114. By Thomas Voß
-
Make the default implementation more verbose.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:114
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 115. By Thomas Voß
-
Make sure that the system state lock instance is around long enough when reaching out via the bus.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:115
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 116. By Thomas Voß
-
We really should release the on request, not the off one.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:116
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 117. By Thomas Voß
-
Make sure that a DisplayStateLock is alive for long enough to always be able to complete a release operation.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:117
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 118. By Thomas Voß
-
* debian/control:
- Removing pre-depends that are not required
- Bumping standards-version to 3.9.6
[ Ricardo Salveti de Araujo ]
* Migrating tests to use ogg instead of mp3/avi removed:
tests/h264.avi tests/test.mp3 added: tests/test-audio-1. ogg
tests/test-video. ogg tests/test.mp3 renamed: tests/test.ogg =>
tests/test-audio. ogg
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:118
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 119. By Thomas Voß
-
Tighten scope in StateController.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:119
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'src/core/media/CMakeLists.txt' |
2 | --- src/core/media/CMakeLists.txt 2015-03-19 20:49:44 +0000 |
3 | +++ src/core/media/CMakeLists.txt 2015-03-19 20:49:45 +0000 |
4 | @@ -90,8 +90,12 @@ |
5 | hybris_client_death_observer.cpp |
6 | cover_art_resolver.cpp |
7 | engine.cpp |
8 | + |
9 | + power/state_controller.cpp |
10 | + |
11 | recorder_observer.cpp |
12 | hybris_recorder_observer.cpp |
13 | + |
14 | gstreamer/engine.cpp |
15 | gstreamer/playbin.cpp |
16 | |
17 | |
18 | === added file 'src/core/media/external_services.h' |
19 | --- src/core/media/external_services.h 1970-01-01 00:00:00 +0000 |
20 | +++ src/core/media/external_services.h 2015-03-19 20:49:45 +0000 |
21 | @@ -0,0 +1,83 @@ |
22 | +/* |
23 | + * Copyright © 2014 Canonical Ltd. |
24 | + * |
25 | + * This program is free software: you can redistribute it and/or modify it |
26 | + * under the terms of the GNU Lesser General Public License version 3, |
27 | + * as published by the Free Software Foundation. |
28 | + * |
29 | + * This program is distributed in the hope that it will be useful, |
30 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
31 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
32 | + * GNU Lesser General Public License for more details. |
33 | + * |
34 | + * You should have received a copy of the GNU Lesser General Public License |
35 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
36 | + * |
37 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
38 | + */ |
39 | +#ifndef CORE_UBUNTU_MEDIA_EXTERNAL_SERVICES_H_ |
40 | +#define CORE_UBUNTU_MEDIA_EXTERNAL_SERVICES_H_ |
41 | + |
42 | +#include <core/dbus/bus.h> |
43 | + |
44 | +#include <core/dbus/asio/executor.h> |
45 | + |
46 | +#include <boost/asio.hpp> |
47 | + |
48 | +namespace core |
49 | +{ |
50 | +namespace ubuntu |
51 | +{ |
52 | +namespace media |
53 | +{ |
54 | +namespace helper |
55 | +{ |
56 | +// A helper struct that bundles: |
57 | +// * a dispatcher, i.e., the io_service |
58 | +// * access to the system and session bus |
59 | +// |
60 | +// In addtion, it allows us to mock out services and |
61 | +// for acceptance testing purposes. |
62 | +struct ExternalServices |
63 | +{ |
64 | + ExternalServices(const core::dbus::Bus::Ptr& session, const core::dbus::Bus::Ptr& system) |
65 | + : keep_alive{io_service}, |
66 | + session{session}, |
67 | + system{system} |
68 | + { |
69 | + } |
70 | + |
71 | + ExternalServices() |
72 | + : ExternalServices |
73 | + { |
74 | + core::dbus::Bus::Ptr{new core::dbus::Bus{core::dbus::WellKnownBus::session}}, |
75 | + core::dbus::Bus::Ptr{new core::dbus::Bus{core::dbus::WellKnownBus::system}} |
76 | + } |
77 | + { |
78 | + session->install_executor(core::dbus::asio::make_executor(session, io_service)); |
79 | + system->install_executor(core::dbus::asio::make_executor(system, io_service)); |
80 | + } |
81 | + |
82 | + |
83 | + void run() |
84 | + { |
85 | + io_service.run(); |
86 | + } |
87 | + |
88 | + void stop() |
89 | + { |
90 | + io_service.stop(); |
91 | + } |
92 | + |
93 | + boost::asio::io_service io_service; |
94 | + boost::asio::io_service::work keep_alive; |
95 | + |
96 | + core::dbus::Bus::Ptr session; |
97 | + core::dbus::Bus::Ptr system; |
98 | +}; |
99 | +} |
100 | +} |
101 | +} |
102 | +} |
103 | + |
104 | +#endif // CORE_UBUNTU_MEDIA_EXTERNAL_SERVICES_H_ |
105 | |
106 | === modified file 'src/core/media/player_implementation.cpp' |
107 | --- src/core/media/player_implementation.cpp 2015-03-19 20:49:44 +0000 |
108 | +++ src/core/media/player_implementation.cpp 2015-03-19 20:49:45 +0000 |
109 | @@ -25,8 +25,6 @@ |
110 | #include "engine.h" |
111 | #include "track_list_implementation.h" |
112 | |
113 | -#include "powerd_service.h" |
114 | -#include "unity_screen_service.h" |
115 | #include "gstreamer/engine.h" |
116 | |
117 | #include <memory> |
118 | @@ -52,45 +50,50 @@ |
119 | WAKELOCK_CLEAR_INVALID |
120 | }; |
121 | |
122 | - Private(PlayerImplementation* parent, |
123 | - const dbus::types::ObjectPath& session_path, |
124 | - const std::shared_ptr<media::Service>& service, |
125 | - PlayerImplementation::PlayerKey key) |
126 | + Private(PlayerImplementation* parent, const media::PlayerImplementation::Configuration& config) |
127 | : parent(parent), |
128 | - service(service), |
129 | + config(config), |
130 | + display_state_lock(config.power_state_controller->display_state_lock()), |
131 | + system_state_lock(config.power_state_controller->system_state_lock()), |
132 | engine(std::make_shared<gstreamer::Engine>()), |
133 | - session_path(session_path), |
134 | track_list( |
135 | new media::TrackListImplementation( |
136 | - session_path.as_string() + "/TrackList", |
137 | + config.session->path().as_string() + "/TrackList", |
138 | engine->meta_data_extractor())), |
139 | - sys_lock_name("media-hub-music-playback"), |
140 | - disp_cookie(-1), |
141 | system_wakelock_count(0), |
142 | display_wakelock_count(0), |
143 | previous_state(Engine::State::stopped), |
144 | - key(key), |
145 | engine_state_change_connection(engine->state().changed().connect(make_state_change_handler())) |
146 | { |
147 | - auto bus = std::shared_ptr<dbus::Bus>(new dbus::Bus(core::dbus::WellKnownBus::system)); |
148 | - bus->install_executor(dbus::asio::make_executor(bus)); |
149 | - |
150 | - auto stub_service = dbus::Service::use_service(bus, dbus::traits::Service<core::Powerd>::interface_name()); |
151 | - powerd_session = stub_service->object_for_path(dbus::types::ObjectPath("/com/canonical/powerd")); |
152 | - |
153 | - auto uscreen_stub_service = dbus::Service::use_service(bus, dbus::traits::Service<core::UScreen>::interface_name()); |
154 | - uscreen_session = uscreen_stub_service->object_for_path(dbus::types::ObjectPath("/com/canonical/Unity/Screen")); |
155 | - |
156 | - auto client_death_observer = media::platform_default_client_death_observer(); |
157 | - |
158 | - client_death_observer->register_for_death_notifications_with_key(key); |
159 | - client_death_observer->on_client_with_key_died().connect([this](const media::Player::PlayerKey& died) |
160 | + config.client_death_observer->register_for_death_notifications_with_key(config.key); |
161 | + config.client_death_observer->on_client_with_key_died().connect([this](const media::Player::PlayerKey& died) |
162 | { |
163 | - if (died != this->key) |
164 | + if (died != this->config.key) |
165 | return; |
166 | |
167 | on_client_died(); |
168 | }); |
169 | + |
170 | + // Poor man's logging of release/acquire events. |
171 | + display_state_lock->acquired().connect([](media::power::DisplayState state) |
172 | + { |
173 | + std::cout << "Acquired new display state: " << state << std::endl; |
174 | + }); |
175 | + |
176 | + display_state_lock->released().connect([](media::power::DisplayState state) |
177 | + { |
178 | + std::cout << "Released display state: " << state << std::endl; |
179 | + }); |
180 | + |
181 | + system_state_lock->acquired().connect([](media::power::SystemState state) |
182 | + { |
183 | + std::cout << "Acquired new system state: " << state << std::endl; |
184 | + }); |
185 | + |
186 | + system_state_lock->released().connect([](media::power::SystemState state) |
187 | + { |
188 | + std::cout << "Released system state: " << state << std::endl; |
189 | + }); |
190 | } |
191 | |
192 | ~Private() |
193 | @@ -170,22 +173,16 @@ |
194 | { |
195 | if (++display_wakelock_count == 1) |
196 | { |
197 | - auto result = uscreen_session->invoke_method_synchronously<core::UScreen::keepDisplayOn, int>(); |
198 | - if (result.is_error()) |
199 | - throw std::runtime_error(result.error().print()); |
200 | - disp_cookie = result.value(); |
201 | - cout << "Requested new display wakelock" << endl; |
202 | + display_state_lock->request_acquire(media::power::DisplayState::on); |
203 | + std::cout << "Requested new display wakelock." << std::endl; |
204 | } |
205 | } |
206 | else |
207 | { |
208 | if (++system_wakelock_count == 1) |
209 | { |
210 | - auto result = powerd_session->invoke_method_synchronously<core::Powerd::requestSysState, std::string>(sys_lock_name, static_cast<int>(1)); |
211 | - if (result.is_error()) |
212 | - throw std::runtime_error(result.error().print()); |
213 | - sys_cookie = result.value(); |
214 | - cout << "Requested new system wakelock" << endl; |
215 | + system_state_lock->request_acquire(media::power::SystemState::active); |
216 | + std::cout << "Requested new system wakelock." << std::endl; |
217 | } |
218 | } |
219 | } |
220 | @@ -209,18 +206,16 @@ |
221 | // Only actually clear the system wakelock once the count reaches zero |
222 | if (--system_wakelock_count == 0) |
223 | { |
224 | - cout << "Clearing system wakelock" << endl; |
225 | - powerd_session->invoke_method_synchronously<core::Powerd::clearSysState, void>(sys_cookie); |
226 | - sys_cookie.clear(); |
227 | + std::cout << "Clearing system wakelock." << std::endl; |
228 | + system_state_lock->request_release(media::power::SystemState::active); |
229 | } |
230 | break; |
231 | case wakelock_clear_t::WAKELOCK_CLEAR_DISPLAY: |
232 | // Only actually clear the display wakelock once the count reaches zero |
233 | if (--display_wakelock_count == 0) |
234 | { |
235 | - cout << "Clearing display wakelock" << endl; |
236 | - uscreen_session->invoke_method_synchronously<core::UScreen::removeDisplayOnRequest, void>(disp_cookie); |
237 | - disp_cookie = -1; |
238 | + std::cout << "Clearing display wakelock." << std::endl; |
239 | + display_state_lock->request_release(media::power::DisplayState::on); |
240 | } |
241 | break; |
242 | case wakelock_clear_t::WAKELOCK_CLEAR_INVALID: |
243 | @@ -275,44 +270,33 @@ |
244 | engine->reset(); |
245 | } |
246 | |
247 | - PlayerImplementation* parent; |
248 | - std::shared_ptr<Service> service; |
249 | + // Our link back to our parent. |
250 | + media::PlayerImplementation* parent; |
251 | + // We just store the parameters passed on construction. |
252 | + media::PlayerImplementation::Configuration config; |
253 | + media::power::StateController::Lock<media::power::DisplayState>::Ptr display_state_lock; |
254 | + media::power::StateController::Lock<media::power::SystemState>::Ptr system_state_lock; |
255 | + |
256 | std::shared_ptr<Engine> engine; |
257 | - dbus::types::ObjectPath session_path; |
258 | std::shared_ptr<TrackListImplementation> track_list; |
259 | - std::shared_ptr<dbus::Object> powerd_session; |
260 | - std::shared_ptr<dbus::Object> uscreen_session; |
261 | - std::string sys_lock_name; |
262 | - int disp_cookie; |
263 | - std::string sys_cookie; |
264 | std::atomic<int> system_wakelock_count; |
265 | std::atomic<int> display_wakelock_count; |
266 | Engine::State previous_state; |
267 | - PlayerImplementation::PlayerKey key; |
268 | core::Signal<> on_client_disconnected; |
269 | core::Connection engine_state_change_connection; |
270 | }; |
271 | |
272 | -media::PlayerImplementation::PlayerImplementation( |
273 | - const std::string& identity, |
274 | - const std::shared_ptr<core::dbus::Bus>& bus, |
275 | - const std::shared_ptr<core::dbus::Object>& session, |
276 | - const std::shared_ptr<Service>& service, |
277 | - PlayerKey key) |
278 | +media::PlayerImplementation::PlayerImplementation(const media::PlayerImplementation::Configuration& config) |
279 | : media::PlayerSkeleton |
280 | { |
281 | media::PlayerSkeleton::Configuration |
282 | { |
283 | - bus, |
284 | - session, |
285 | - identity |
286 | + config.bus, |
287 | + config.session, |
288 | + config.identity |
289 | } |
290 | }, |
291 | - d(make_shared<Private>( |
292 | - this, |
293 | - session->path(), |
294 | - service, |
295 | - key)) |
296 | + d{std::make_shared<Private>(this, config)} |
297 | { |
298 | // Initialize default values for Player interface properties |
299 | can_play().set(true); |
300 | @@ -464,7 +448,7 @@ |
301 | // TODO: Convert this to be a property instead of sync call |
302 | media::Player::PlayerKey media::PlayerImplementation::key() const |
303 | { |
304 | - return d->key; |
305 | + return d->config.key; |
306 | } |
307 | |
308 | media::video::Sink::Ptr media::PlayerImplementation::create_gl_texture_video_sink(std::uint32_t texture_id) |
309 | |
310 | === modified file 'src/core/media/player_implementation.h' |
311 | --- src/core/media/player_implementation.h 2015-03-19 20:49:44 +0000 |
312 | +++ src/core/media/player_implementation.h 2015-03-19 20:49:45 +0000 |
313 | @@ -21,6 +21,9 @@ |
314 | |
315 | #include "player_skeleton.h" |
316 | |
317 | +#include "client_death_observer.h" |
318 | +#include "power/state_controller.h" |
319 | + |
320 | #include <memory> |
321 | |
322 | namespace core |
323 | @@ -35,12 +38,21 @@ |
324 | class PlayerImplementation : public PlayerSkeleton |
325 | { |
326 | public: |
327 | - PlayerImplementation( |
328 | - const std::string& identity, |
329 | - const std::shared_ptr<core::dbus::Bus>& bus, |
330 | - const std::shared_ptr<core::dbus::Object>& session, |
331 | - const std::shared_ptr<Service>& service, |
332 | - PlayerKey key); |
333 | + // All creation time arguments go here |
334 | + struct Configuration |
335 | + { |
336 | + std::string identity; |
337 | + std::shared_ptr<core::dbus::Bus> bus; |
338 | + std::shared_ptr<core::dbus::Object> session; |
339 | + std::shared_ptr<Service> service; |
340 | + PlayerKey key; |
341 | + |
342 | + // Functional dependencies |
343 | + ClientDeathObserver::Ptr client_death_observer; |
344 | + power::StateController::Ptr power_state_controller; |
345 | + }; |
346 | + |
347 | + PlayerImplementation(const Configuration& configuration); |
348 | ~PlayerImplementation(); |
349 | |
350 | virtual std::shared_ptr<TrackList> track_list(); |
351 | |
352 | === added directory 'src/core/media/power' |
353 | === added file 'src/core/media/power/state_controller.cpp' |
354 | --- src/core/media/power/state_controller.cpp 1970-01-01 00:00:00 +0000 |
355 | +++ src/core/media/power/state_controller.cpp 2015-03-19 20:49:45 +0000 |
356 | @@ -0,0 +1,360 @@ |
357 | +/* |
358 | + * Copyright © 2014 Canonical Ltd. |
359 | + * |
360 | + * This program is free software: you can redistribute it and/or modify it |
361 | + * under the terms of the GNU Lesser General Public License version 3, |
362 | + * as published by the Free Software Foundation. |
363 | + * |
364 | + * This program is distributed in the hope that it will be useful, |
365 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
366 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
367 | + * GNU Lesser General Public License for more details. |
368 | + * |
369 | + * You should have received a copy of the GNU Lesser General Public License |
370 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
371 | + * |
372 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
373 | + */ |
374 | + |
375 | +#include <core/media/power/state_controller.h> |
376 | + |
377 | +#include <core/dbus/macros.h> |
378 | +#include <core/dbus/object.h> |
379 | + |
380 | +#include <iostream> |
381 | + |
382 | +namespace media = core::ubuntu::media; |
383 | + |
384 | +namespace com { namespace canonical { |
385 | +struct Unity |
386 | +{ |
387 | + struct Screen |
388 | + { |
389 | + static const std::string& name() |
390 | + { |
391 | + static std::string s = "com.canonical.Unity.Screen"; |
392 | + return s; |
393 | + } |
394 | + |
395 | + static const core::dbus::types::ObjectPath& path() |
396 | + { |
397 | + static core::dbus::types::ObjectPath p{"/com/canonical/Unity/Screen"}; |
398 | + return p; |
399 | + } |
400 | + |
401 | + DBUS_CPP_METHOD_DEF(keepDisplayOn, Screen) |
402 | + DBUS_CPP_METHOD_DEF(removeDisplayOnRequest, Screen) |
403 | + }; |
404 | +}; |
405 | +namespace powerd { |
406 | +struct Interface |
407 | +{ |
408 | + static std::string& name() |
409 | + { |
410 | + static std::string s = "com.canonical.powerd"; |
411 | + return s; |
412 | + } |
413 | + |
414 | + static const core::dbus::types::ObjectPath& path() |
415 | + { |
416 | + static core::dbus::types::ObjectPath p{"/com/canonical/powerd"}; |
417 | + return p; |
418 | + } |
419 | + |
420 | + DBUS_CPP_METHOD_DEF(requestSysState, com::canonical::powerd::Interface) |
421 | + DBUS_CPP_METHOD_DEF(clearSysState, com::canonical::powerd::Interface) |
422 | +}; |
423 | +}}} |
424 | + |
425 | +namespace |
426 | +{ |
427 | +namespace impl |
428 | +{ |
429 | +struct DisplayStateLock : public media::power::StateController::Lock<media::power::DisplayState>, |
430 | + public std::enable_shared_from_this<DisplayStateLock> |
431 | +{ |
432 | + // To safe us some typing |
433 | + typedef std::shared_ptr<DisplayStateLock> Ptr; |
434 | + |
435 | + // We postpone releasing the display for this amount of time. |
436 | + static boost::posix_time::seconds timeout_for_release() |
437 | + { |
438 | + return boost::posix_time::seconds{4}; |
439 | + } |
440 | + |
441 | + // The invalid cookie marker. |
442 | + static constexpr const std::int32_t the_invalid_cookie{-1}; |
443 | + |
444 | + DisplayStateLock(const media::power::StateController::Ptr& parent, |
445 | + boost::asio::io_service& io_service, |
446 | + const core::dbus::Object::Ptr& object) |
447 | + : parent{parent}, |
448 | + timeout{io_service}, |
449 | + object{object}, |
450 | + cookie{the_invalid_cookie} |
451 | + { |
452 | + } |
453 | + |
454 | + // From core::ubuntu::media::power::StateController::Lock<DisplayState> |
455 | + void request_acquire(media::power::DisplayState state) override |
456 | + { |
457 | + if (state == media::power::DisplayState::off) |
458 | + return; |
459 | + |
460 | + std::weak_ptr<DisplayStateLock> wp{shared_from_this()}; |
461 | + |
462 | + object->invoke_method_asynchronously_with_callback<com::canonical::Unity::Screen::keepDisplayOn, std::int32_t>( |
463 | + [wp, state](const core::dbus::Result<std::int32_t>& result) |
464 | + { |
465 | + if (result.is_error()) |
466 | + { |
467 | + std::cerr << result.error().print() << std::endl; |
468 | + return; |
469 | + } |
470 | + |
471 | + if (auto sp = wp.lock()) |
472 | + { |
473 | + sp->cookie = result.value(); |
474 | + sp->signals.acquired(state); |
475 | + } |
476 | + }); |
477 | + } |
478 | + |
479 | + void request_release(media::power::DisplayState state) override |
480 | + { |
481 | + if (state == media::power::DisplayState::off) |
482 | + return; |
483 | + |
484 | + if (cookie == the_invalid_cookie) |
485 | + return; |
486 | + |
487 | + // We make sure that we keep ourselves alive to make sure |
488 | + // that release requests are always correctly issued. |
489 | + auto sp = shared_from_this(); |
490 | + |
491 | + auto current_cookie(cookie); |
492 | + |
493 | + timeout.expires_from_now(timeout_for_release()); |
494 | + timeout.async_wait([sp, state, current_cookie](const boost::system::error_code& ec) |
495 | + { |
496 | + // We only return early from the timeout handler if the operation has been |
497 | + // explicitly aborted before. |
498 | + if (ec == boost::asio::error::operation_aborted) |
499 | + return; |
500 | + |
501 | + sp->object->invoke_method_asynchronously_with_callback<com::canonical::Unity::Screen::removeDisplayOnRequest, void>( |
502 | + [sp, state, current_cookie](const core::dbus::Result<void>& result) |
503 | + { |
504 | + if (result.is_error()) |
505 | + { |
506 | + std::cerr << result.error().print() << std::endl; |
507 | + return; |
508 | + } |
509 | + |
510 | + sp->signals.released(state); |
511 | + |
512 | + // We might have issued a different request before and |
513 | + // only call the display state done if the original cookie |
514 | + // corresponds to the one we just gave up. |
515 | + if (sp->cookie == current_cookie) |
516 | + sp->cookie = the_invalid_cookie; |
517 | + |
518 | + }, current_cookie); |
519 | + }); |
520 | + } |
521 | + |
522 | + // Emitted whenever the acquire request completes. |
523 | + const core::Signal<media::power::DisplayState>& acquired() const override |
524 | + { |
525 | + return signals.acquired; |
526 | + } |
527 | + |
528 | + // Emitted whenever the release request completes. |
529 | + const core::Signal<media::power::DisplayState>& released() const override |
530 | + { |
531 | + return signals.released; |
532 | + } |
533 | + |
534 | + media::power::StateController::Ptr parent; |
535 | + boost::asio::deadline_timer timeout; |
536 | + core::dbus::Object::Ptr object; |
537 | + std::int32_t cookie; |
538 | + |
539 | + struct |
540 | + { |
541 | + core::Signal<media::power::DisplayState> acquired; |
542 | + core::Signal<media::power::DisplayState> released; |
543 | + } signals; |
544 | +}; |
545 | + |
546 | +struct SystemStateLock : public media::power::StateController::Lock<media::power::SystemState>, |
547 | + public std::enable_shared_from_this<SystemStateLock> |
548 | +{ |
549 | + static constexpr const char* wake_lock_name |
550 | + { |
551 | + "media-hub-playback_lock" |
552 | + }; |
553 | + |
554 | + SystemStateLock(const media::power::StateController::Ptr& parent, const core::dbus::Object::Ptr& object) |
555 | + : parent{parent}, |
556 | + object{object} |
557 | + { |
558 | + } |
559 | + |
560 | + // Informs the system that the caller would like |
561 | + // the system to stay active. |
562 | + void request_acquire(media::power::SystemState state) override |
563 | + { |
564 | + if (state == media::power::SystemState::suspend) |
565 | + return; |
566 | + |
567 | + // Keep scope of this lock tight as to avoid |
568 | + // deadlocks on PlayerImplementation destruction |
569 | + { |
570 | + std::lock_guard<std::mutex> lg{system_state_cookie_store_guard}; |
571 | + if (system_state_cookie_store.count(state) > 0) |
572 | + return; |
573 | + } |
574 | + |
575 | + std::weak_ptr<SystemStateLock> wp{shared_from_this()}; |
576 | + |
577 | + object->invoke_method_asynchronously_with_callback<com::canonical::powerd::Interface::requestSysState, std::string>([wp, state](const core::dbus::Result<std::string>& result) |
578 | + { |
579 | + if (result.is_error()) // TODO(tvoss): We should log the error condition here. |
580 | + return; |
581 | + |
582 | + if (auto sp = wp.lock()) |
583 | + { |
584 | + std::lock_guard<std::mutex> lg{sp->system_state_cookie_store_guard}; |
585 | + |
586 | + sp->system_state_cookie_store[state] = result.value(); |
587 | + sp->signals.acquired(state); |
588 | + } |
589 | + }, std::string{wake_lock_name}, static_cast<std::int32_t>(state)); |
590 | + } |
591 | + |
592 | + // Informs the system that the caller does not |
593 | + // require the system to stay active anymore. |
594 | + void request_release(media::power::SystemState state) override |
595 | + { |
596 | + if (state == media::power::SystemState::suspend) |
597 | + return; |
598 | + |
599 | + std::lock_guard<std::mutex> lg{system_state_cookie_store_guard}; |
600 | + |
601 | + if (system_state_cookie_store.count(state) == 0) |
602 | + return; |
603 | + |
604 | + std::weak_ptr<SystemStateLock> wp{shared_from_this()}; |
605 | + |
606 | + object->invoke_method_asynchronously_with_callback<com::canonical::powerd::Interface::clearSysState, void>([wp, state](const core::dbus::Result<void>& result) |
607 | + { |
608 | + if (result.is_error()) |
609 | + std::cerr << result.error().print() << std::endl; |
610 | + |
611 | + if (auto sp = wp.lock()) |
612 | + { |
613 | + std::lock_guard<std::mutex> lg{sp->system_state_cookie_store_guard}; |
614 | + |
615 | + sp->system_state_cookie_store.erase(state); |
616 | + sp->signals.released(state); |
617 | + } |
618 | + }, system_state_cookie_store.at(state)); |
619 | + } |
620 | + |
621 | + // Emitted whenever the acquire request completes. |
622 | + const core::Signal<media::power::SystemState>& acquired() const override |
623 | + { |
624 | + return signals.acquired; |
625 | + } |
626 | + |
627 | + // Emitted whenever the release request completes. |
628 | + const core::Signal<media::power::SystemState>& released() const override |
629 | + { |
630 | + return signals.released; |
631 | + } |
632 | + |
633 | + // Guards concurrent accesses to the cookie store. |
634 | + std::mutex system_state_cookie_store_guard; |
635 | + // Maps previously requested system states to the cookies returned |
636 | + // by the remote end. Used for keeping track of acquired states and |
637 | + // associated cookies to be able to release previously granted acquisitions. |
638 | + std::map<media::power::SystemState, std::string> system_state_cookie_store; |
639 | + media::power::StateController::Ptr parent; |
640 | + core::dbus::Object::Ptr object; |
641 | + struct |
642 | + { |
643 | + core::Signal<media::power::SystemState> acquired; |
644 | + core::Signal<media::power::SystemState> released; |
645 | + } signals; |
646 | +}; |
647 | + |
648 | +struct StateController : public media::power::StateController, |
649 | + public std::enable_shared_from_this<impl::StateController> |
650 | +{ |
651 | + StateController(media::helper::ExternalServices& es) |
652 | + : external_services{es}, |
653 | + powerd |
654 | + { |
655 | + core::dbus::Service::use_service<com::canonical::powerd::Interface>(external_services.system) |
656 | + ->object_for_path(com::canonical::powerd::Interface::path()) |
657 | + }, |
658 | + unity_screen |
659 | + { |
660 | + core::dbus::Service::use_service<com::canonical::Unity::Screen>(external_services.system) |
661 | + ->object_for_path(com::canonical::Unity::Screen::path()) |
662 | + } |
663 | + { |
664 | + } |
665 | + |
666 | + media::power::StateController::Lock<media::power::SystemState>::Ptr system_state_lock() override |
667 | + { |
668 | + return std::make_shared<impl::SystemStateLock>(shared_from_this(), powerd); |
669 | + } |
670 | + |
671 | + media::power::StateController::Lock<media::power::DisplayState>::Ptr display_state_lock() override |
672 | + { |
673 | + return std::make_shared<impl::DisplayStateLock>(shared_from_this(), external_services.io_service, unity_screen); |
674 | + } |
675 | + |
676 | + media::helper::ExternalServices& external_services; |
677 | + core::dbus::Object::Ptr powerd; |
678 | + core::dbus::Object::Ptr unity_screen; |
679 | +}; |
680 | +} |
681 | +} |
682 | + |
683 | +media::power::StateController::Ptr media::power::make_platform_default_state_controller(core::ubuntu::media::helper::ExternalServices& external_services) |
684 | +{ |
685 | + return std::make_shared<impl::StateController>(external_services); |
686 | +} |
687 | + |
688 | +// operator<< pretty prints the given display state to the given output stream. |
689 | +std::ostream& media::power::operator<<(std::ostream& out, media::power::DisplayState state) |
690 | +{ |
691 | + switch (state) |
692 | + { |
693 | + case media::power::DisplayState::off: |
694 | + return out << "DisplayState::off"; |
695 | + case media::power::DisplayState::on: |
696 | + return out << "DisplayState::on"; |
697 | + } |
698 | + |
699 | + return out; |
700 | +} |
701 | + |
702 | +// operator<< pretty prints the given system state to the given output stream. |
703 | +std::ostream& media::power::operator<<(std::ostream& out, media::power::SystemState state) |
704 | +{ |
705 | + switch (state) |
706 | + { |
707 | + case media::power::SystemState::active: |
708 | + return out << "SystemState::active"; |
709 | + case media::power::SystemState::blank_on_proximity: |
710 | + return out << "SystemState::blank_on_proximity"; |
711 | + case media::power::SystemState::suspend: |
712 | + return out << "SystemState::suspend"; |
713 | + } |
714 | + |
715 | + return out; |
716 | +} |
717 | |
718 | === added file 'src/core/media/power/state_controller.h' |
719 | --- src/core/media/power/state_controller.h 1970-01-01 00:00:00 +0000 |
720 | +++ src/core/media/power/state_controller.h 2015-03-19 20:49:45 +0000 |
721 | @@ -0,0 +1,108 @@ |
722 | +/* |
723 | + * Copyright © 2014 Canonical Ltd. |
724 | + * |
725 | + * This program is free software: you can redistribute it and/or modify it |
726 | + * under the terms of the GNU Lesser General Public License version 3, |
727 | + * as published by the Free Software Foundation. |
728 | + * |
729 | + * This program is distributed in the hope that it will be useful, |
730 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
731 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
732 | + * GNU Lesser General Public License for more details. |
733 | + * |
734 | + * You should have received a copy of the GNU Lesser General Public License |
735 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
736 | + * |
737 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
738 | + */ |
739 | +#ifndef CORE_UBUNTU_MEDIA_POWER_STATE_CONTROLLER_H_ |
740 | +#define CORE_UBUNTU_MEDIA_POWER_STATE_CONTROLLER_H_ |
741 | + |
742 | +#include <core/media/external_services.h> |
743 | + |
744 | +#include <core/property.h> |
745 | + |
746 | +#include <iosfwd> |
747 | +#include <memory> |
748 | + |
749 | +namespace core |
750 | +{ |
751 | +namespace ubuntu |
752 | +{ |
753 | +namespace media |
754 | +{ |
755 | +namespace power |
756 | +{ |
757 | +// Enumerates all known power states of a display. |
758 | +enum class DisplayState |
759 | +{ |
760 | + // The display is off. |
761 | + off = 0, |
762 | + // The display is on. |
763 | + on = 1 |
764 | +}; |
765 | + |
766 | +// Enumerates known power states of the system. |
767 | +enum class SystemState |
768 | +{ |
769 | + // Note that callers will be notified of suspend state changes |
770 | + // but may not request this state. |
771 | + suspend = 0, |
772 | + // The Active state will prevent system suspend |
773 | + active = 1, |
774 | + // Substate of Active with disabled proximity based blanking |
775 | + blank_on_proximity = 2 |
776 | +}; |
777 | + |
778 | +// Interface that enables observation of the system power state. |
779 | +struct StateController |
780 | +{ |
781 | + // To save us some typing. |
782 | + typedef std::shared_ptr<StateController> Ptr; |
783 | + |
784 | + // When acquired, ensures that the system stays active, |
785 | + // and decreases the reference count when released. |
786 | + template<typename State> |
787 | + struct Lock |
788 | + { |
789 | + // To save us some typing. |
790 | + typedef std::shared_ptr<Lock> Ptr; |
791 | + |
792 | + Lock() = default; |
793 | + virtual ~Lock() = default; |
794 | + |
795 | + // Informs the system that the caller would like |
796 | + // the system to stay active. |
797 | + virtual void request_acquire(State state) = 0; |
798 | + // Informs the system that the caller does not |
799 | + // require the system to stay active anymore. |
800 | + virtual void request_release(State state) = 0; |
801 | + |
802 | + // Emitted whenever the acquire request completes. |
803 | + virtual const core::Signal<State>& acquired() const = 0; |
804 | + // Emitted whenever the release request completes. |
805 | + virtual const core::Signal<State>& released() const = 0; |
806 | + }; |
807 | + |
808 | + StateController() = default; |
809 | + virtual ~StateController() = default; |
810 | + |
811 | + // Returns a power::StateController::Lock<DisplayState> instance. |
812 | + virtual Lock<DisplayState>::Ptr display_state_lock() = 0; |
813 | + // Returns a power::StateController::Lock<SystemState> instance. |
814 | + virtual Lock<SystemState>::Ptr system_state_lock() = 0; |
815 | +}; |
816 | + |
817 | +// Creates a StateController instance that connects to the platform default |
818 | +// services to control system and display power states. |
819 | +StateController::Ptr make_platform_default_state_controller(core::ubuntu::media::helper::ExternalServices&); |
820 | + |
821 | +// operator<< pretty prints the given display state to the given output stream. |
822 | +std::ostream& operator<<(std::ostream& out, DisplayState state); |
823 | +// operator<< pretty prints the given system state to the given output stream. |
824 | +std::ostream& operator<<(std::ostream& out, SystemState state); |
825 | +} |
826 | +} |
827 | +} |
828 | +} |
829 | +#endif // CORE_UBUNTU_MEDIA_POWER_STATE_CONTROLLER_H_ |
830 | |
831 | === removed file 'src/core/media/powerd_service.h' |
832 | --- src/core/media/powerd_service.h 2014-08-08 14:36:29 +0000 |
833 | +++ src/core/media/powerd_service.h 1970-01-01 00:00:00 +0000 |
834 | @@ -1,73 +0,0 @@ |
835 | -/* |
836 | - * Copyright (C) 2014 Canonical Ltd |
837 | - * |
838 | - * This program is free software: you can redistribute it and/or modify |
839 | - * it under the terms of the GNU Lesser General Public License version 3 as |
840 | - * published by the Free Software Foundation. |
841 | - * |
842 | - * This program is distributed in the hope that it will be useful, |
843 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
844 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
845 | - * GNU Lesser General Public License for more details. |
846 | - * |
847 | - * You should have received a copy of the GNU Lesser General Public License |
848 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
849 | - * |
850 | - * Author: Ricardo Mendoza <ricardo.mendoza@canonical.com> |
851 | - */ |
852 | - |
853 | -#include <core/dbus/dbus.h> |
854 | -#include <core/dbus/fixture.h> |
855 | -#include <core/dbus/object.h> |
856 | -#include <core/dbus/property.h> |
857 | -#include <core/dbus/service.h> |
858 | -#include <core/dbus/interfaces/properties.h> |
859 | -#include <core/dbus/types/stl/tuple.h> |
860 | -#include <core/dbus/types/stl/vector.h> |
861 | - |
862 | -#include <core/dbus/asio/executor.h> |
863 | - |
864 | -#include <string> |
865 | -#include <vector> |
866 | -#include <chrono> |
867 | - |
868 | -namespace core |
869 | -{ |
870 | - |
871 | -struct Powerd |
872 | -{ |
873 | - static std::string& name() |
874 | - { |
875 | - static std::string s = "com.canonical.powerd"; |
876 | - return s; |
877 | - } |
878 | - |
879 | - struct requestSysState |
880 | - { |
881 | - static std::string name() |
882 | - { |
883 | - static std::string s = "requestSysState"; |
884 | - return s; |
885 | - } |
886 | - |
887 | - static const std::chrono::milliseconds default_timeout() { return std::chrono::seconds{1}; } |
888 | - |
889 | - typedef Powerd Interface; |
890 | - }; |
891 | - |
892 | - struct clearSysState |
893 | - { |
894 | - static std::string name() |
895 | - { |
896 | - static std::string s = "clearSysState"; |
897 | - return s; |
898 | - } |
899 | - |
900 | - static const std::chrono::milliseconds default_timeout() { return std::chrono::seconds{1}; } |
901 | - |
902 | - typedef Powerd Interface; |
903 | - }; |
904 | - |
905 | -}; |
906 | - |
907 | -} |
908 | |
909 | === modified file 'src/core/media/server/server.cpp' |
910 | --- src/core/media/server/server.cpp 2014-04-04 14:31:43 +0000 |
911 | +++ src/core/media/server/server.cpp 2015-03-19 20:49:45 +0000 |
912 | @@ -20,24 +20,137 @@ |
913 | #include <core/media/player.h> |
914 | #include <core/media/track_list.h> |
915 | |
916 | -#include <hybris/media/media_codec_layer.h> |
917 | - |
918 | #include "core/media/service_implementation.h" |
919 | |
920 | +#include <core/posix/signal.h> |
921 | + |
922 | #include <iostream> |
923 | |
924 | namespace media = core::ubuntu::media; |
925 | |
926 | using namespace std; |
927 | |
928 | +#if defined(MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER) |
929 | +#include <hybris/media/media_codec_layer.h> |
930 | + |
931 | +namespace |
932 | +{ |
933 | +// All platform-specific initialization routines go here. |
934 | +void platform_init() |
935 | +{ |
936 | + decoding_service_init(); |
937 | +} |
938 | +} |
939 | +#else // MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER |
940 | +namespace |
941 | +{ |
942 | +// All platform-specific initialization routines go here. |
943 | +void platform_init() |
944 | +{ |
945 | + // Consciously left empty |
946 | +} |
947 | +} |
948 | +#endif // MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER |
949 | + |
950 | int main() |
951 | { |
952 | - // Init hybris-level DecodingService |
953 | - decoding_service_init(); |
954 | - cout << "Starting DecodingService..." << endl; |
955 | - |
956 | - auto service = std::make_shared<media::ServiceImplementation>(); |
957 | - service->run(); |
958 | + auto trap = core::posix::trap_signals_for_all_subsequent_threads( |
959 | + { |
960 | + core::posix::Signal::sig_int, |
961 | + core::posix::Signal::sig_term |
962 | + }); |
963 | + |
964 | + trap->signal_raised().connect([trap](core::posix::Signal) |
965 | + { |
966 | + trap->stop(); |
967 | + }); |
968 | + |
969 | + // Init platform-specific functionality. |
970 | + platform_init(); |
971 | + |
972 | + // We keep track of our state. |
973 | + bool shutdown_requested{false}; |
974 | + |
975 | + // Our helper for connecting to external services. |
976 | + core::ubuntu::media::helper::ExternalServices external_services; |
977 | + |
978 | + // We move communication with all external services to its own worker thread |
979 | + // to keep the actual service thread free from such operations. |
980 | + std::thread external_services_worker |
981 | + { |
982 | + // We keep on running until shutdown has been explicitly requested. |
983 | + // All exceptions thrown on this thread are caught, and reported to |
984 | + // the terminal for post-mortem debugging purposes. |
985 | + [&shutdown_requested, &external_services]() |
986 | + { |
987 | + while (not shutdown_requested) |
988 | + { |
989 | + try |
990 | + { |
991 | + // Blocking call to the underlying reactor implementation. |
992 | + // Only returns cleanly when explicitly stopped. |
993 | + external_services.io_service.run(); |
994 | + } |
995 | + catch (const std::exception& e) |
996 | + { |
997 | + std::cerr << "Error while executing the underlying io_service: " << e.what() << std::endl; |
998 | + } |
999 | + catch (...) |
1000 | + { |
1001 | + std::cerr << "Error while executing the underlying io_service." << std::endl; |
1002 | + } |
1003 | + } |
1004 | + } |
1005 | + }; |
1006 | + |
1007 | + // We assemble the configuration for executing the service now. |
1008 | + media::ServiceImplementation::Configuration service_config |
1009 | + { |
1010 | + external_services |
1011 | + }; |
1012 | + |
1013 | + auto service = std::make_shared<media::ServiceImplementation>(service_config); |
1014 | + |
1015 | + std::thread service_worker |
1016 | + { |
1017 | + [&shutdown_requested, service]() |
1018 | + { |
1019 | + while (not shutdown_requested) |
1020 | + { |
1021 | + try |
1022 | + { |
1023 | + service->run(); |
1024 | + } |
1025 | + catch (const std::exception& e) |
1026 | + { |
1027 | + std::cerr << "Recoverable error while executing the service: " << e.what() << std::endl; |
1028 | + } |
1029 | + catch (...) |
1030 | + { |
1031 | + std::cerr << "Recoverable error while executing the service." << std::endl; |
1032 | + } |
1033 | + } |
1034 | + } |
1035 | + }; |
1036 | + |
1037 | + // We block on waiting for signals telling us to gracefully shutdown. |
1038 | + // Incoming signals are handled in a lambda connected to signal_raised() |
1039 | + // which is setup at the beginning of main(...). |
1040 | + trap->run(); |
1041 | + |
1042 | + // Inform our workers that we should shutdown gracefully |
1043 | + shutdown_requested = true; |
1044 | + |
1045 | + // And stop execution of helper and actual service. |
1046 | + service->stop(); |
1047 | + |
1048 | + if (service_worker.joinable()) |
1049 | + service_worker.join(); |
1050 | + |
1051 | + external_services.stop(); |
1052 | + |
1053 | + if (external_services_worker.joinable()) |
1054 | + external_services_worker.join(); |
1055 | |
1056 | return 0; |
1057 | } |
1058 | |
1059 | === modified file 'src/core/media/service_implementation.cpp' |
1060 | --- src/core/media/service_implementation.cpp 2015-03-19 20:49:44 +0000 |
1061 | +++ src/core/media/service_implementation.cpp 2015-03-19 20:49:45 +0000 |
1062 | @@ -22,6 +22,7 @@ |
1063 | |
1064 | #include "service_implementation.h" |
1065 | |
1066 | +#include "client_death_observer.h" |
1067 | #include "indicator_power_service.h" |
1068 | #include "call-monitor/call_monitor.h" |
1069 | #include "player_configuration.h" |
1070 | @@ -40,7 +41,6 @@ |
1071 | #include <pulse/pulseaudio.h> |
1072 | |
1073 | #include "util/timeout.h" |
1074 | -#include "unity_screen_service.h" |
1075 | |
1076 | namespace media = core::ubuntu::media; |
1077 | |
1078 | @@ -48,10 +48,13 @@ |
1079 | |
1080 | struct media::ServiceImplementation::Private |
1081 | { |
1082 | - Private() |
1083 | - : resume_key(std::numeric_limits<std::uint32_t>::max()), |
1084 | - keep_alive(io_service), |
1085 | - disp_cookie(0), |
1086 | + Private(const ServiceImplementation::Configuration& configuration) |
1087 | + : configuration(configuration), |
1088 | + resume_key(std::numeric_limits<std::uint32_t>::max()), |
1089 | + power_state_controller(media::power::make_platform_default_state_controller(configuration.external_services)), |
1090 | + display_state_lock(power_state_controller->display_state_lock()), |
1091 | + client_death_observer(media::platform_default_client_death_observer()), |
1092 | + recorder_observer(media::make_platform_default_recorder_observer()), |
1093 | pulse_mainloop_api(nullptr), |
1094 | pulse_context(nullptr), |
1095 | headphones_connected(false), |
1096 | @@ -59,13 +62,6 @@ |
1097 | primary_idx(-1), |
1098 | call_monitor(new CallMonitor) |
1099 | { |
1100 | - bus = std::shared_ptr<dbus::Bus>(new dbus::Bus(core::dbus::WellKnownBus::session)); |
1101 | - bus->install_executor(dbus::asio::make_executor(bus, io_service)); |
1102 | - worker = std::move(std::thread([this]() |
1103 | - { |
1104 | - bus->run(); |
1105 | - })); |
1106 | - |
1107 | // Spawn pulse watchdog |
1108 | pulse_mainloop = nullptr; |
1109 | pulse_worker = std::move(std::thread([this]() |
1110 | @@ -129,19 +125,11 @@ |
1111 | |
1112 | // Connect the property change signal that will allow media-hub to take appropriate action |
1113 | // when the battery level reaches critical |
1114 | - auto stub_service = dbus::Service::use_service(bus, "com.canonical.indicator.power"); |
1115 | + auto stub_service = dbus::Service::use_service(configuration.external_services.session, "com.canonical.indicator.power"); |
1116 | indicator_power_session = stub_service->object_for_path(dbus::types::ObjectPath("/com/canonical/indicator/power/Battery")); |
1117 | power_level = indicator_power_session->get_property<core::IndicatorPower::PowerLevel>(); |
1118 | is_warning = indicator_power_session->get_property<core::IndicatorPower::IsWarning>(); |
1119 | |
1120 | - // Obtain session with Unity.Screen so that we request state when doing recording |
1121 | - auto bus = std::shared_ptr<dbus::Bus>(new dbus::Bus(core::dbus::WellKnownBus::system)); |
1122 | - bus->install_executor(dbus::asio::make_executor(bus)); |
1123 | - |
1124 | - auto uscreen_stub_service = dbus::Service::use_service(bus, dbus::traits::Service<core::UScreen>::interface_name()); |
1125 | - uscreen_session = uscreen_stub_service->object_for_path(dbus::types::ObjectPath("/com/canonical/Unity/Screen")); |
1126 | - |
1127 | - recorder_observer = media::make_platform_default_recorder_observer(); |
1128 | recorder_observer->recording_state().changed().connect([this](media::RecordingState state) |
1129 | { |
1130 | media_recording_state_changed(state); |
1131 | @@ -159,42 +147,20 @@ |
1132 | pulse_mainloop = nullptr; |
1133 | } |
1134 | |
1135 | - bus->stop(); |
1136 | - |
1137 | - if (worker.joinable()) |
1138 | - worker.join(); |
1139 | - |
1140 | if (pulse_worker.joinable()) |
1141 | pulse_worker.join(); |
1142 | } |
1143 | |
1144 | void media_recording_state_changed(media::RecordingState state) |
1145 | { |
1146 | - if (uscreen_session == nullptr) |
1147 | - return; |
1148 | - |
1149 | if (state == media::RecordingState::started) |
1150 | { |
1151 | - if (disp_cookie > 0) |
1152 | - return; |
1153 | - |
1154 | - // Make sure we pause all playback sessions so that it doesn't interfere with recorded audio |
1155 | + display_state_lock->request_acquire(media::power::DisplayState::on); |
1156 | pause_playback(); |
1157 | - |
1158 | - auto result = uscreen_session->invoke_method_synchronously<core::UScreen::keepDisplayOn, int>(); |
1159 | - if (result.is_error()) |
1160 | - throw std::runtime_error(result.error().print()); |
1161 | - disp_cookie = result.value(); |
1162 | } |
1163 | else if (state == media::RecordingState::stopped) |
1164 | { |
1165 | - if (disp_cookie != -1) |
1166 | - { |
1167 | - timeout(4000, true, [this](){ |
1168 | - this->uscreen_session->invoke_method_synchronously<core::UScreen::removeDisplayOnRequest, void>(this->disp_cookie); |
1169 | - this->disp_cookie = -1; |
1170 | - }); |
1171 | - } |
1172 | + display_state_lock->request_release(media::power::DisplayState::on); |
1173 | } |
1174 | } |
1175 | |
1176 | @@ -441,18 +407,16 @@ |
1177 | } |
1178 | } |
1179 | |
1180 | + media::ServiceImplementation::Configuration configuration; |
1181 | // This holds the key of the multimedia role Player instance that was paused |
1182 | // when the battery level reached 10% or 5% |
1183 | - media::Player::PlayerKey resume_key; |
1184 | - std::thread worker; |
1185 | - dbus::Bus::Ptr bus; |
1186 | - boost::asio::io_service io_service; |
1187 | - boost::asio::io_service::work keep_alive; |
1188 | + media::Player::PlayerKey resume_key; |
1189 | std::shared_ptr<dbus::Object> indicator_power_session; |
1190 | std::shared_ptr<core::dbus::Property<core::IndicatorPower::PowerLevel>> power_level; |
1191 | std::shared_ptr<core::dbus::Property<core::IndicatorPower::IsWarning>> is_warning; |
1192 | - int disp_cookie; |
1193 | - std::shared_ptr<dbus::Object> uscreen_session; |
1194 | + media::power::StateController::Ptr power_state_controller; |
1195 | + media::power::StateController::Lock<media::power::DisplayState>::Ptr display_state_lock; |
1196 | + media::ClientDeathObserver::Ptr client_death_observer; |
1197 | media::RecorderObserver::Ptr recorder_observer; |
1198 | // Pulse-specific |
1199 | pa_mainloop_api *pulse_mainloop_api; |
1200 | @@ -474,7 +438,7 @@ |
1201 | std::list<media::Player::PlayerKey> paused_sessions; |
1202 | }; |
1203 | |
1204 | -media::ServiceImplementation::ServiceImplementation() : d(new Private()) |
1205 | +media::ServiceImplementation::ServiceImplementation(const Configuration& configuration) : d(new Private(configuration)) |
1206 | { |
1207 | d->power_level->changed().connect([this](const core::IndicatorPower::PowerLevel::ValueType &level) |
1208 | { |
1209 | @@ -520,8 +484,16 @@ |
1210 | std::shared_ptr<media::Player> media::ServiceImplementation::create_session( |
1211 | const media::Player::Configuration& conf) |
1212 | { |
1213 | - auto player = std::make_shared<media::PlayerImplementation>( |
1214 | - conf.identity, conf.bus, conf.session, shared_from_this(), conf.key); |
1215 | + auto player = std::make_shared<media::PlayerImplementation>(media::PlayerImplementation::Configuration |
1216 | + { |
1217 | + conf.identity, |
1218 | + conf.bus, |
1219 | + conf.session, |
1220 | + shared_from_this(), |
1221 | + conf.key, |
1222 | + d->client_death_observer, |
1223 | + d->power_state_controller |
1224 | + }); |
1225 | |
1226 | auto key = conf.key; |
1227 | player->on_client_disconnected().connect([this, key]() |
1228 | @@ -531,7 +503,7 @@ |
1229 | // remove_player_for_key can destroy the player instance which in turn |
1230 | // destroys the "on_client_disconnected" signal whose destructor will wait |
1231 | // until all dispatches are done |
1232 | - d->io_service.post([this, key]() |
1233 | + d->configuration.external_services.io_service.post([this, key]() |
1234 | { |
1235 | if (!has_player_for_key(key)) |
1236 | return; |
1237 | |
1238 | === modified file 'src/core/media/service_implementation.h' |
1239 | --- src/core/media/service_implementation.h 2015-01-16 17:17:30 +0000 |
1240 | +++ src/core/media/service_implementation.h 2015-03-19 20:49:45 +0000 |
1241 | @@ -20,6 +20,7 @@ |
1242 | #define CORE_UBUNTU_MEDIA_SERVICE_IMPLEMENTATION_H_ |
1243 | |
1244 | #include "service_skeleton.h" |
1245 | +#include "external_services.h" |
1246 | |
1247 | namespace core |
1248 | { |
1249 | @@ -27,13 +28,18 @@ |
1250 | { |
1251 | namespace media |
1252 | { |
1253 | - |
1254 | class Player; |
1255 | |
1256 | class ServiceImplementation : public ServiceSkeleton |
1257 | { |
1258 | public: |
1259 | - ServiceImplementation (); |
1260 | + // All creation time arguments go here. |
1261 | + struct Configuration |
1262 | + { |
1263 | + helper::ExternalServices& external_services; |
1264 | + }; |
1265 | + |
1266 | + ServiceImplementation (const Configuration& configuration); |
1267 | ~ServiceImplementation (); |
1268 | |
1269 | std::shared_ptr<Player> create_session(const Player::Configuration&); |
1270 | |
1271 | === removed file 'src/core/media/unity_screen_service.h' |
1272 | --- src/core/media/unity_screen_service.h 2014-06-16 22:28:53 +0000 |
1273 | +++ src/core/media/unity_screen_service.h 1970-01-01 00:00:00 +0000 |
1274 | @@ -1,72 +0,0 @@ |
1275 | -/* |
1276 | - * Copyright (C) 2014 Canonical Ltd |
1277 | - * |
1278 | - * This program is free software: you can redistribute it and/or modify |
1279 | - * it under the terms of the GNU Lesser General Public License version 3 as |
1280 | - * published by the Free Software Foundation. |
1281 | - * |
1282 | - * This program is distributed in the hope that it will be useful, |
1283 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1284 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1285 | - * GNU Lesser General Public License for more details. |
1286 | - * |
1287 | - * You should have received a copy of the GNU Lesser General Public License |
1288 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1289 | - * |
1290 | - * Author: Alberto Aguirre <alberto.aguirre@canonical.com> |
1291 | - */ |
1292 | - |
1293 | -#include <core/dbus/dbus.h> |
1294 | -#include <core/dbus/fixture.h> |
1295 | -#include <core/dbus/object.h> |
1296 | -#include <core/dbus/property.h> |
1297 | -#include <core/dbus/service.h> |
1298 | -#include <core/dbus/interfaces/properties.h> |
1299 | -#include <core/dbus/types/stl/tuple.h> |
1300 | -#include <core/dbus/types/stl/vector.h> |
1301 | - |
1302 | -#include <core/dbus/asio/executor.h> |
1303 | - |
1304 | -#include <string> |
1305 | -#include <vector> |
1306 | -#include <chrono> |
1307 | - |
1308 | -namespace core |
1309 | -{ |
1310 | - |
1311 | -struct UScreen |
1312 | -{ |
1313 | - static std::string& name() |
1314 | - { |
1315 | - static std::string s = "com.canonical.Unity.Screen"; |
1316 | - return s; |
1317 | - } |
1318 | - |
1319 | - struct keepDisplayOn |
1320 | - { |
1321 | - static std::string name() |
1322 | - { |
1323 | - static std::string s = "keepDisplayOn"; |
1324 | - return s; |
1325 | - } |
1326 | - |
1327 | - static const std::chrono::milliseconds default_timeout() { return std::chrono::seconds{1}; } |
1328 | - |
1329 | - typedef UScreen Interface; |
1330 | - }; |
1331 | - |
1332 | - struct removeDisplayOnRequest |
1333 | - { |
1334 | - static std::string name() |
1335 | - { |
1336 | - static std::string s = "removeDisplayOnRequest"; |
1337 | - return s; |
1338 | - } |
1339 | - |
1340 | - static const std::chrono::milliseconds default_timeout() { return std::chrono::seconds{1}; } |
1341 | - |
1342 | - typedef UScreen Interface; |
1343 | - }; |
1344 | -}; |
1345 | - |
1346 | -} |
1347 | |
1348 | === modified file 'tests/CMakeLists.txt' |
1349 | --- tests/CMakeLists.txt 2014-02-14 08:12:35 +0000 |
1350 | +++ tests/CMakeLists.txt 2015-03-19 20:49:45 +0000 |
1351 | @@ -50,5 +50,5 @@ |
1352 | "COM_UBUNTU_MEDIA_SERVICE_AUDIO_SINK_NAME=fakesink" |
1353 | ) |
1354 | |
1355 | -add_subdirectory(acceptance-tests) |
1356 | +# add_subdirectory(acceptance-tests) |
1357 | add_subdirectory(unit-tests) |
FAILED: Continuous integration, rev:104 jenkins. qa.ubuntu. com/job/ media-hub- ci/181/ jenkins. qa.ubuntu. com/job/ media-hub- vivid-amd64- ci/21/console jenkins. qa.ubuntu. com/job/ media-hub- vivid-armhf- ci/21/console jenkins. qa.ubuntu. com/job/ media-hub- vivid-i386- ci/21/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/media- hub-ci/ 181/rebuild
http://