Merge lp:~justinmcp/media-hub/proxy-player into lp:media-hub
- proxy-player
- Merge into trunk
Status: | Approved |
---|---|
Approved by: | Jim Hodapp |
Approved revision: | 165 |
Proposed branch: | lp:~justinmcp/media-hub/proxy-player |
Merge into: | lp:media-hub |
Diff against target: |
917 lines (+625/-17) 19 files modified
CMakeLists.txt (+1/-1) debian/VERSION (+1/-1) debian/VERSION.vivid (+1/-1) debian/changelog (+6/-0) include/core/media/player.h (+8/-0) src/core/media/CMakeLists.txt (+1/-0) src/core/media/codec.h (+40/-0) src/core/media/player.cpp (+13/-0) src/core/media/player_configuration.h (+2/-0) src/core/media/player_implementation.cpp (+6/-0) src/core/media/player_implementation.h (+1/-0) src/core/media/player_stub.cpp (+12/-3) src/core/media/player_stub.h (+3/-1) src/core/media/proxy_player_implementation.cpp (+404/-0) src/core/media/proxy_player_implementation.h (+90/-0) src/core/media/service_implementation.cpp (+21/-6) src/core/media/service_implementation.h (+3/-0) src/core/media/service_skeleton.cpp (+5/-0) src/core/media/service_stub.cpp (+7/-4) |
To merge this branch: | bzr merge lp:~justinmcp/media-hub/proxy-player |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jim Hodapp (community) | code | Approve | |
PS Jenkins bot | continuous-integration | Needs Fixing | |
Santosh | Pending | ||
Review via email:
|
Commit message
Support for external media players managed by media-hub.
Description of the change
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Justin McPherson (justinmcp) : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Jim Hodapp (jhodapp) : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:155
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https:/
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 156. By Justin McPherson
-
Merge from trunk.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:156
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https:/
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Jim Hodapp (jhodapp) : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Justin McPherson (justinmcp) : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Jim Hodapp (jhodapp) : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Justin McPherson (justinmcp) : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Jim Hodapp (jhodapp) : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Jim Hodapp (jhodapp) wrote : | # |
Several comments inline below after doing a more thorough code review. Also, this MR needs syncing with the latest media-hub branch which includes the use of a new logging facility instead of using cout/cerr.
- 157. By Justin McPherson
-
Enable variant session type through the Player Configuration structure.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Jim Hodapp (jhodapp) wrote : | # |
This is definitely what I had in mind and looks great. Thanks for doing it. A couple of minor comments inline below and then you just need to double check the client_death_cb related handling. Also, make sure to rebase this branch from trunk and convert to using the Logger instead of cout/cerr.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Justin McPherson (justinmcp) : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Justin McPherson (justinmcp) : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Jim Hodapp (jhodapp) : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Justin McPherson (justinmcp) : | # |
- 158. By Justin McPherson
-
Remove unneeded dbus method definition
- 159. By Justin McPherson
-
Merge from trunk.
- 160. By Justin McPherson
-
- Use new logging functionality
- Fix en/decoding of PlayerType
- Return a default player type if type arg is unknown
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Jim Hodapp (jhodapp) : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Jim Hodapp (jhodapp) wrote : | # |
Also I was curious how you've been testing this out? Does it already link to Oxide in some way?
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Justin McPherson (justinmcp) wrote : | # |
Sometime ago, this branch was working with https:/
- 161. By Justin McPherson
-
Rename PlayerType enum values.
rigged -> standard
proxy -> proxied - 162. By Justin McPherson
-
Renable test
- 163. By Justin McPherson
-
Changelog entry
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Jim Hodapp (jhodapp) wrote : | # |
You don't need an explicit changelog entry here. Going through the silo process will take the commit message from LP and add a changelog entry.
- 164. By Justin McPherson
-
Remove entry
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Robert Bruce Park (robru) wrote : | # |
Please don't delete debian/changelog. Just revert all your changes to debian/changelog and then everything should work fine.
- 165. By Justin McPherson
-
Fix changelog
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Justin McPherson (justinmcp) wrote : | # |
Before my morning coffee, apologies, the latter was meant, the former was done. Fixed...
- 166. By Justin McPherson
-
Support for older compilers.
- 167. By Justin McPherson
-
Bump version number
- 168. By Justin McPherson
-
Update version is VERSION* files
- 169. By Justin McPherson
-
Merge from trunk.
- 170. By Justin McPherson
-
Fix build
- 171. By Justin McPherson
-
Merge from trunk.
- 172. By Justin McPherson
-
Merge from trunk.
Unmerged revisions
- 172. By Justin McPherson
-
Merge from trunk.
- 171. By Justin McPherson
-
Merge from trunk.
- 170. By Justin McPherson
-
Fix build
- 169. By Justin McPherson
-
Merge from trunk.
- 168. By Justin McPherson
-
Update version is VERSION* files
- 167. By Justin McPherson
-
Bump version number
- 166. By Justin McPherson
-
Support for older compilers.
- 165. By Justin McPherson
-
Fix changelog
- 164. By Justin McPherson
-
Remove entry
- 163. By Justin McPherson
-
Changelog entry
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2016-07-19 21:16:56 +0000 |
3 | +++ CMakeLists.txt 2016-08-03 01:04:26 +0000 |
4 | @@ -20,7 +20,7 @@ |
5 | # we define the version to be 5.0.0 |
6 | if (${DISTRO_CODENAME} STREQUAL "vivid") |
7 | set(UBUNTU_MEDIA_HUB_VERSION_MAJOR 4) |
8 | - set(UBUNTU_MEDIA_HUB_VERSION_MINOR 5) |
9 | + set(UBUNTU_MEDIA_HUB_VERSION_MINOR 6) |
10 | set(UBUNTU_MEDIA_HUB_VERSION_PATCH 0) |
11 | else () |
12 | set(UBUNTU_MEDIA_HUB_VERSION_MAJOR 5) |
13 | |
14 | === modified file 'debian/VERSION' |
15 | --- debian/VERSION 2015-12-16 16:50:37 +0000 |
16 | +++ debian/VERSION 2016-08-03 01:04:26 +0000 |
17 | @@ -1,1 +1,1 @@ |
18 | -5.0.0 |
19 | \ No newline at end of file |
20 | +5.2.0 |
21 | |
22 | === modified file 'debian/VERSION.vivid' |
23 | --- debian/VERSION.vivid 2015-12-16 16:50:37 +0000 |
24 | +++ debian/VERSION.vivid 2016-08-03 01:04:26 +0000 |
25 | @@ -1,1 +1,1 @@ |
26 | -4.1.0 |
27 | \ No newline at end of file |
28 | +4.6.0 |
29 | |
30 | === modified file 'debian/changelog' |
31 | --- debian/changelog 2016-07-20 21:28:28 +0000 |
32 | +++ debian/changelog 2016-08-03 01:04:26 +0000 |
33 | @@ -1,3 +1,9 @@ |
34 | +media-hub (4.6.0+16.10.20160720-0ubuntu1) yakkety; urgency=medium |
35 | + |
36 | + * Add support for external players managed by media-hub. |
37 | + |
38 | + -- Justin McPherson <justin.mcpherson@canonical.com> Mon, 20 Jun 2016 08:58:18 +1000 |
39 | + |
40 | media-hub (4.5.0+16.10.20160720-0ubuntu1) yakkety; urgency=medium |
41 | |
42 | * Emit client side signal when the dbus connection between |
43 | |
44 | === modified file 'include/core/media/player.h' |
45 | --- include/core/media/player.h 2016-06-01 00:43:04 +0000 |
46 | +++ include/core/media/player.h 2016-08-03 01:04:26 +0000 |
47 | @@ -75,6 +75,7 @@ |
48 | Client() = delete; |
49 | |
50 | static const Configuration& default_configuration(); |
51 | + static const Configuration& proxy_configuration(); |
52 | }; |
53 | |
54 | enum PlaybackStatus |
55 | @@ -130,6 +131,12 @@ |
56 | service_missing_error |
57 | }; |
58 | |
59 | + enum PlayerType |
60 | + { |
61 | + standard, |
62 | + proxied |
63 | + }; |
64 | + |
65 | Player(const Player&) = delete; |
66 | virtual ~Player(); |
67 | |
68 | @@ -142,6 +149,7 @@ |
69 | |
70 | virtual std::shared_ptr<TrackList> track_list() = 0; |
71 | virtual PlayerKey key() const = 0; |
72 | + virtual PlayerType type() const = 0; |
73 | |
74 | virtual video::Sink::Ptr create_gl_texture_video_sink(std::uint32_t texture_id) = 0; |
75 | |
76 | |
77 | === modified file 'src/core/media/CMakeLists.txt' |
78 | --- src/core/media/CMakeLists.txt 2016-06-15 17:49:49 +0000 |
79 | +++ src/core/media/CMakeLists.txt 2016-08-03 01:04:26 +0000 |
80 | @@ -121,6 +121,7 @@ |
81 | |
82 | player_skeleton.cpp |
83 | player_implementation.cpp |
84 | + proxy_player_implementation.cpp |
85 | service_skeleton.cpp |
86 | service_implementation.cpp |
87 | track_list_skeleton.cpp |
88 | |
89 | === modified file 'src/core/media/codec.h' |
90 | --- src/core/media/codec.h 2016-06-14 19:41:18 +0000 |
91 | +++ src/core/media/codec.h 2016-08-03 01:04:26 +0000 |
92 | @@ -235,6 +235,46 @@ |
93 | namespace helper |
94 | { |
95 | template<> |
96 | +struct TypeMapper<core::ubuntu::media::Player::PlayerType> |
97 | +{ |
98 | + constexpr static ArgumentType type_value() |
99 | + { |
100 | + return core::dbus::ArgumentType::int16; |
101 | + } |
102 | + constexpr static bool is_basic_type() |
103 | + { |
104 | + return false; |
105 | + } |
106 | + constexpr static bool requires_signature() |
107 | + { |
108 | + return false; |
109 | + } |
110 | + |
111 | + static std::string signature() |
112 | + { |
113 | + static const std::string s = TypeMapper<std::int16_t>::signature(); |
114 | + return s; |
115 | + } |
116 | +}; |
117 | +} |
118 | + |
119 | +template<> |
120 | +struct Codec<core::ubuntu::media::Player::PlayerType> |
121 | +{ |
122 | + static void encode_argument(core::dbus::Message::Writer& out, const core::ubuntu::media::Player::PlayerType& in) |
123 | + { |
124 | + out.push_int16(static_cast<std::int16_t>(in)); |
125 | + } |
126 | + |
127 | + static void decode_argument(core::dbus::Message::Reader& out, core::ubuntu::media::Player::PlayerType& in) |
128 | + { |
129 | + in = static_cast<core::ubuntu::media::Player::PlayerType>(out.pop_int16()); |
130 | + } |
131 | +}; |
132 | + |
133 | +namespace helper |
134 | +{ |
135 | +template<> |
136 | struct TypeMapper<core::ubuntu::media::Player::AudioStreamRole> |
137 | { |
138 | constexpr static ArgumentType type_value() |
139 | |
140 | === modified file 'src/core/media/player.cpp' |
141 | --- src/core/media/player.cpp 2016-02-19 16:14:42 +0000 |
142 | +++ src/core/media/player.cpp 2016-08-03 01:04:26 +0000 |
143 | @@ -43,6 +43,19 @@ |
144 | { |
145 | static const media::Player::Configuration config |
146 | { |
147 | + Player::standard, |
148 | + 0, |
149 | + nullptr, |
150 | + nullptr |
151 | + }; |
152 | + return config; |
153 | +} |
154 | + |
155 | +const media::Player::Configuration& media::Player::Client::proxy_configuration() |
156 | +{ |
157 | + static const media::Player::Configuration config |
158 | + { |
159 | + Player::proxied, |
160 | 0, |
161 | nullptr, |
162 | nullptr |
163 | |
164 | === modified file 'src/core/media/player_configuration.h' |
165 | --- src/core/media/player_configuration.h 2016-04-20 14:42:41 +0000 |
166 | +++ src/core/media/player_configuration.h 2016-08-03 01:04:26 +0000 |
167 | @@ -28,6 +28,8 @@ |
168 | // to the implementation in a way that is opaque to the client. |
169 | struct core::ubuntu::media::Player::Configuration |
170 | { |
171 | + // Type of player backing this session |
172 | + core::ubuntu::media::Player::PlayerType type; |
173 | // Unique key for identifying the session path. |
174 | core::ubuntu::media::Player::PlayerKey key; |
175 | // The bus connection to expose objects on. |
176 | |
177 | === modified file 'src/core/media/player_implementation.cpp' |
178 | --- src/core/media/player_implementation.cpp 2016-07-11 01:21:38 +0000 |
179 | +++ src/core/media/player_implementation.cpp 2016-08-03 01:04:26 +0000 |
180 | @@ -844,6 +844,12 @@ |
181 | } |
182 | |
183 | template<typename Parent> |
184 | +media::Player::PlayerType media::PlayerImplementation<Parent>::type() const |
185 | +{ |
186 | + return Player::standard; |
187 | +} |
188 | + |
189 | +template<typename Parent> |
190 | media::video::Sink::Ptr media::PlayerImplementation<Parent>::create_gl_texture_video_sink(std::uint32_t texture_id) |
191 | { |
192 | d->engine->create_video_sink(texture_id); |
193 | |
194 | === modified file 'src/core/media/player_implementation.h' |
195 | --- src/core/media/player_implementation.h 2015-04-17 16:37:02 +0000 |
196 | +++ src/core/media/player_implementation.h 2016-08-03 01:04:26 +0000 |
197 | @@ -61,6 +61,7 @@ |
198 | |
199 | virtual std::shared_ptr<TrackList> track_list(); |
200 | virtual Player::PlayerKey key() const; |
201 | + virtual Player::PlayerType type() const; |
202 | |
203 | virtual video::Sink::Ptr create_gl_texture_video_sink(std::uint32_t texture_id); |
204 | |
205 | |
206 | === modified file 'src/core/media/player_stub.cpp' |
207 | --- src/core/media/player_stub.cpp 2016-07-19 21:22:18 +0000 |
208 | +++ src/core/media/player_stub.cpp 2016-08-03 01:04:26 +0000 |
209 | @@ -48,11 +48,13 @@ |
210 | Private(const std::shared_ptr<Service>& parent, |
211 | const std::shared_ptr<core::dbus::Service>& service, |
212 | const std::shared_ptr<core::dbus::Object>& object, |
213 | - const std::string& uuid |
214 | + const std::string& uuid, |
215 | + PlayerType type |
216 | ) : parent(parent), |
217 | service(service), |
218 | object(object), |
219 | key(object->invoke_method_synchronously<mpris::Player::Key, media::Player::PlayerKey>().value()), |
220 | + type(type), |
221 | uuid(uuid), |
222 | sink_factory(media::video::make_platform_default_sink_factory(key)), |
223 | properties |
224 | @@ -102,6 +104,7 @@ |
225 | dbus::Service::Ptr service; |
226 | dbus::Object::Ptr object; |
227 | media::Player::PlayerKey key; |
228 | + media::Player::PlayerType type; |
229 | std::string uuid; |
230 | media::video::SinkFactory sink_factory; |
231 | struct |
232 | @@ -234,8 +237,9 @@ |
233 | const std::shared_ptr<Service>& parent, |
234 | const std::shared_ptr<core::dbus::Service>& service, |
235 | const std::shared_ptr<core::dbus::Object>& object, |
236 | - const std::string& uuid) |
237 | - : d(new Private{parent, service, object, uuid}) |
238 | + const std::string& uuid, |
239 | + media::Player::PlayerType type) |
240 | + : d(new Private{parent, service, object, uuid, type}) |
241 | { |
242 | } |
243 | |
244 | @@ -278,6 +282,11 @@ |
245 | return d->key; |
246 | } |
247 | |
248 | +media::Player::PlayerType media::PlayerStub::type() const |
249 | +{ |
250 | + return d->type; |
251 | +} |
252 | + |
253 | bool media::PlayerStub::open_uri(const media::Track::UriType& uri) |
254 | { |
255 | const auto op = d->object->transact_method<mpris::Player::OpenUri, bool>(uri); |
256 | |
257 | === modified file 'src/core/media/player_stub.h' |
258 | --- src/core/media/player_stub.h 2016-06-01 00:43:04 +0000 |
259 | +++ src/core/media/player_stub.h 2016-08-03 01:04:26 +0000 |
260 | @@ -41,7 +41,8 @@ |
261 | const std::shared_ptr<Service>& parent, |
262 | const std::shared_ptr<core::dbus::Service>& service, |
263 | const std::shared_ptr<core::dbus::Object>& object, |
264 | - const std::string& uuid = std::string{}); |
265 | + const std::string& uuid = std::string{}, |
266 | + PlayerType type = PlayerType::standard); |
267 | |
268 | ~PlayerStub(); |
269 | |
270 | @@ -51,6 +52,7 @@ |
271 | |
272 | virtual std::shared_ptr<TrackList> track_list(); |
273 | virtual PlayerKey key() const; |
274 | + virtual PlayerType type() const; |
275 | |
276 | virtual video::Sink::Ptr create_gl_texture_video_sink(std::uint32_t texture_id); |
277 | |
278 | |
279 | === added file 'src/core/media/proxy_player_implementation.cpp' |
280 | --- src/core/media/proxy_player_implementation.cpp 1970-01-01 00:00:00 +0000 |
281 | +++ src/core/media/proxy_player_implementation.cpp 2016-08-03 01:04:26 +0000 |
282 | @@ -0,0 +1,404 @@ |
283 | +/* |
284 | + * Copyright © 2016 Canonical Ltd. |
285 | + * |
286 | + * This program is free software: you can redistribute it and/or modify it |
287 | + * under the terms of the GNU Lesser General Public License version 3, |
288 | + * as published by the Free Software Foundation. |
289 | + * |
290 | + * This program is distributed in the hope that it will be useful, |
291 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
292 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
293 | + * GNU Lesser General Public License for more details. |
294 | + * |
295 | + * You should have received a copy of the GNU Lesser General Public License |
296 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
297 | + * |
298 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
299 | + * Jim Hodapp <jim.hodapp@canonical.com> |
300 | + * Justin McPherson <justin.mcpherson@canonical.com> |
301 | + */ |
302 | + |
303 | +#include "proxy_player_implementation.h" |
304 | +#include "util/timeout.h" |
305 | + |
306 | +#include <unistd.h> |
307 | + |
308 | +#include "client_death_observer.h" |
309 | +#include "track_list_implementation.h" |
310 | + |
311 | +#include "core/media/logger/logger.h" |
312 | + |
313 | +#include <memory> |
314 | +#include <exception> |
315 | +#include <iostream> |
316 | +#include <mutex> |
317 | + |
318 | +namespace media = core::ubuntu::media; |
319 | +namespace dbus = core::dbus; |
320 | + |
321 | +using namespace std; |
322 | + |
323 | +template<typename Parent> |
324 | +struct media::ProxyPlayerImplementation<Parent>::Private : |
325 | + public std::enable_shared_from_this<Private> |
326 | +{ |
327 | + enum class wakelock_clear_t |
328 | + { |
329 | + WAKELOCK_CLEAR_INACTIVE, |
330 | + WAKELOCK_CLEAR_DISPLAY, |
331 | + WAKELOCK_CLEAR_SYSTEM, |
332 | + WAKELOCK_CLEAR_INVALID |
333 | + }; |
334 | + |
335 | + Private(ProxyPlayerImplementation* parent, const media::ProxyPlayerImplementation<Parent>::Configuration& config) |
336 | + : parent(parent), |
337 | + config(config), |
338 | + display_state_lock(config.power_state_controller->display_state_lock()), |
339 | + system_state_lock(config.power_state_controller->system_state_lock()), |
340 | + system_wakelock_count(0), |
341 | + display_wakelock_count(0), |
342 | + previous_state(media::Player::stopped), |
343 | + state(media::Player::null) |
344 | + { |
345 | + // Poor man's logging of release/acquire events. |
346 | + display_state_lock->acquired().connect([](media::power::DisplayState state) |
347 | + { |
348 | + MH_INFO("Acquired new display state: %s", state); |
349 | + }); |
350 | + |
351 | + display_state_lock->released().connect([](media::power::DisplayState state) |
352 | + { |
353 | + MH_INFO("Released display state: %s", state); |
354 | + }); |
355 | + |
356 | + system_state_lock->acquired().connect([](media::power::SystemState state) |
357 | + { |
358 | + MH_INFO("Acquired new system state: %s", state); |
359 | + }); |
360 | + |
361 | + system_state_lock->released().connect([](media::power::SystemState state) |
362 | + { |
363 | + MH_INFO("Released system state: %s", state); |
364 | + }); |
365 | + } |
366 | + |
367 | + ~Private() |
368 | + { |
369 | + // Make sure that we don't hold on to the wakelocks if media-hub-server |
370 | + // ever gets restarted manually or automatically |
371 | + clear_wakelocks(); |
372 | + } |
373 | + |
374 | + void request_power_state() |
375 | + { |
376 | + MH_TRACE(""); |
377 | + try |
378 | + { |
379 | + if (parent->is_video_source()) |
380 | + { |
381 | + if (++display_wakelock_count == 1) |
382 | + { |
383 | + MH_INFO("Requesting new display wakelock."); |
384 | + display_state_lock->request_acquire(media::power::DisplayState::on); |
385 | + MH_INFO("Requested new display wakelock."); |
386 | + } |
387 | + } |
388 | + else |
389 | + { |
390 | + if (++system_wakelock_count == 1) |
391 | + { |
392 | + MH_INFO("Requesting new system wakelock."); |
393 | + system_state_lock->request_acquire(media::power::SystemState::active); |
394 | + MH_INFO("Requested new system wakelock."); |
395 | + } |
396 | + } |
397 | + } |
398 | + catch(const std::exception& e) |
399 | + { |
400 | + MH_WARNING("Failed to request power state: %s", e.what()); |
401 | + } |
402 | + } |
403 | + |
404 | + void clear_wakelock(const wakelock_clear_t &wakelock) |
405 | + { |
406 | + MH_TRACE(""); |
407 | + try |
408 | + { |
409 | + switch (wakelock) |
410 | + { |
411 | + case wakelock_clear_t::WAKELOCK_CLEAR_INACTIVE: |
412 | + break; |
413 | + case wakelock_clear_t::WAKELOCK_CLEAR_SYSTEM: |
414 | + // Only actually clear the system wakelock once the count reaches zero |
415 | + if (--system_wakelock_count == 0) |
416 | + { |
417 | + MH_INFO("Clearing system wakelock."); |
418 | + system_state_lock->request_release(media::power::SystemState::active); |
419 | + } |
420 | + break; |
421 | + case wakelock_clear_t::WAKELOCK_CLEAR_DISPLAY: |
422 | + // Only actually clear the display wakelock once the count reaches zero |
423 | + if (--display_wakelock_count == 0) |
424 | + { |
425 | + MH_INFO("Clearing display wakelock."); |
426 | + display_state_lock->request_release(media::power::DisplayState::on); |
427 | + } |
428 | + break; |
429 | + case wakelock_clear_t::WAKELOCK_CLEAR_INVALID: |
430 | + default: |
431 | + MH_WARNING("Can't clear invalid wakelock type"); |
432 | + } |
433 | + } |
434 | + catch(const std::exception& e) |
435 | + { |
436 | + MH_WARNING("Failed to request clear power state: %s", e.what()); |
437 | + } |
438 | + } |
439 | + |
440 | + wakelock_clear_t current_wakelock_type() const |
441 | + { |
442 | + return (parent->is_video_source()) ? |
443 | + wakelock_clear_t::WAKELOCK_CLEAR_DISPLAY : wakelock_clear_t::WAKELOCK_CLEAR_SYSTEM; |
444 | + } |
445 | + |
446 | + void clear_wakelocks() |
447 | + { |
448 | + // Clear both types of wakelocks (display and system) |
449 | + if (system_wakelock_count.load() > 0) |
450 | + { |
451 | + system_wakelock_count = 1; |
452 | + clear_wakelock(wakelock_clear_t::WAKELOCK_CLEAR_SYSTEM); |
453 | + } |
454 | + if (display_wakelock_count.load() > 0) |
455 | + { |
456 | + display_wakelock_count = 1; |
457 | + clear_wakelock(wakelock_clear_t::WAKELOCK_CLEAR_DISPLAY); |
458 | + } |
459 | + } |
460 | + |
461 | + std::function<void()> make_clear_wakelock_functor() |
462 | + { |
463 | + // Since this functor will be executed on a separate detached thread |
464 | + // the execution of the functor may surpass the lifetime of this Private |
465 | + // object instance. By keeping a weak_ptr to the private object instance |
466 | + // we can check if the object is dead before calling methods on it |
467 | + std::weak_ptr<Private> weak_self{this->shared_from_this()}; |
468 | + auto wakelock_type = current_wakelock_type(); |
469 | + return [weak_self, wakelock_type] { |
470 | + if (auto self = weak_self.lock()) |
471 | + self->clear_wakelock(wakelock_type); |
472 | + }; |
473 | + } |
474 | + |
475 | + void on_client_died() |
476 | + { |
477 | + } |
478 | + |
479 | + void change_state(media::Player::PlaybackStatus state) |
480 | + { |
481 | + switch(state) |
482 | + { |
483 | + case media::Player::playing: |
484 | + { |
485 | + // And update our playback status. |
486 | + parent->playback_status().set(media::Player::playing); |
487 | + |
488 | + request_power_state(); |
489 | + break; |
490 | + } |
491 | + case media::Player::stopped: |
492 | + { |
493 | + parent->playback_status().set(media::Player::stopped); |
494 | + if (previous_state == media::Player::playing) |
495 | + { |
496 | + timeout(4000, true, make_clear_wakelock_functor()); |
497 | + } |
498 | + break; |
499 | + } |
500 | + case media::Player::paused: |
501 | + { |
502 | + parent->playback_status().set(media::Player::paused); |
503 | + if (previous_state == media::Player::playing) |
504 | + { |
505 | + timeout(4000, true, make_clear_wakelock_functor()); |
506 | + } |
507 | + break; |
508 | + } |
509 | + default: |
510 | + break; |
511 | + }; |
512 | + |
513 | + parent->emit_playback_status_changed(state); |
514 | + |
515 | + // Keep track of the previous Engine playback state: |
516 | + previous_state = state; |
517 | + } |
518 | + |
519 | + // Our link back to our parent. |
520 | + media::ProxyPlayerImplementation<Parent>* parent; |
521 | + // We just store the parameters passed on construction. |
522 | + media::ProxyPlayerImplementation<Parent>::Configuration config; |
523 | + media::power::StateController::Lock<media::power::DisplayState>::Ptr display_state_lock; |
524 | + media::power::StateController::Lock<media::power::SystemState>::Ptr system_state_lock; |
525 | + |
526 | + std::shared_ptr<media::TrackListImplementation> track_list; |
527 | + std::atomic<int> system_wakelock_count; |
528 | + std::atomic<int> display_wakelock_count; |
529 | + media::Player::PlaybackStatus previous_state; |
530 | + media::Player::PlaybackStatus state; |
531 | + core::Signal<> on_client_disconnected; |
532 | +}; |
533 | + |
534 | +template<typename Parent> |
535 | +media::ProxyPlayerImplementation<Parent>::ProxyPlayerImplementation(const media::ProxyPlayerImplementation<Parent>::Configuration& config) |
536 | + : Parent{config.parent}, |
537 | + d{std::make_shared<Private>(this, config)} |
538 | +{ |
539 | + // Initialize default values for Player interface properties |
540 | + Parent::can_play().set(true); |
541 | + Parent::can_pause().set(true); |
542 | + Parent::can_seek().set(true); |
543 | + Parent::can_go_previous().set(false); |
544 | + Parent::can_go_next().set(false); |
545 | + Parent::is_video_source().set(true); |
546 | + Parent::is_audio_source().set(false); |
547 | + Parent::shuffle().set(false); |
548 | + Parent::playback_rate().set(1.f); |
549 | + Parent::playback_status().set(Player::PlaybackStatus::null); |
550 | + Parent::loop_status().set(Player::LoopStatus::none); |
551 | + Parent::position().set(0); |
552 | + Parent::duration().set(0); |
553 | + Parent::audio_stream_role().set(Player::AudioStreamRole::multimedia); |
554 | + Parent::orientation().set(Player::Orientation::rotate0); |
555 | + Parent::lifetime().set(Player::Lifetime::normal); |
556 | + |
557 | + // Everything is setup, we now subscribe to death notifications. |
558 | + std::weak_ptr<Private> wp{d}; |
559 | + |
560 | + d->config.client_death_observer->register_for_death_notifications_with_key(config.key); |
561 | + d->config.client_death_observer->on_client_with_key_died().connect([wp](const media::Player::PlayerKey& died) |
562 | + { |
563 | + if (auto sp = wp.lock()) |
564 | + { |
565 | + if (died != sp->config.key) |
566 | + return; |
567 | + |
568 | + static const std::chrono::milliseconds timeout{1000}; |
569 | + media::timeout(timeout.count(), true, [wp]() |
570 | + { |
571 | + if (auto sp = wp.lock()) |
572 | + sp->on_client_died(); |
573 | + }); |
574 | + } |
575 | + }); |
576 | +} |
577 | + |
578 | +template<typename Parent> |
579 | +media::ProxyPlayerImplementation<Parent>::~ProxyPlayerImplementation() |
580 | +{ |
581 | +} |
582 | + |
583 | +template<typename Parent> |
584 | +std::string media::ProxyPlayerImplementation<Parent>::uuid() const |
585 | +{ |
586 | + return std::string{}; |
587 | +} |
588 | + |
589 | +template<typename Parent> |
590 | +void media::ProxyPlayerImplementation<Parent>::reconnect() |
591 | +{ |
592 | + d->config.client_death_observer->register_for_death_notifications_with_key(d->config.key); |
593 | +} |
594 | + |
595 | +template<typename Parent> |
596 | +void media::ProxyPlayerImplementation<Parent>::abandon() |
597 | +{ |
598 | + // Signal client disconnection due to abandonment of player |
599 | + d->on_client_died(); |
600 | +} |
601 | + |
602 | +template<typename Parent> |
603 | +std::shared_ptr<media::TrackList> media::ProxyPlayerImplementation<Parent>::track_list() |
604 | +{ |
605 | + return std::shared_ptr<media::TrackList>(); |
606 | +} |
607 | + |
608 | +template<typename Parent> |
609 | +media::Player::PlayerKey media::ProxyPlayerImplementation<Parent>::key() const |
610 | +{ |
611 | + return d->config.key; |
612 | +} |
613 | + |
614 | +template<typename Parent> |
615 | +media::Player::PlayerType media::ProxyPlayerImplementation<Parent>::type() const |
616 | +{ |
617 | + return Player::proxied; |
618 | +} |
619 | + |
620 | +template<typename Parent> |
621 | +media::video::Sink::Ptr media::ProxyPlayerImplementation<Parent>::create_gl_texture_video_sink(std::uint32_t /*texture_id*/) |
622 | +{ |
623 | + return media::video::Sink::Ptr{}; |
624 | +} |
625 | + |
626 | +template<typename Parent> |
627 | +bool media::ProxyPlayerImplementation<Parent>::open_uri(const Track::UriType& /*uri*/) |
628 | +{ |
629 | + return false; |
630 | +} |
631 | + |
632 | +template<typename Parent> |
633 | +bool media::ProxyPlayerImplementation<Parent>::open_uri(const Track::UriType& /*uri*/, const Player::HeadersType& /*headers*/) |
634 | +{ |
635 | + return false; |
636 | +} |
637 | + |
638 | +template<typename Parent> |
639 | +void media::ProxyPlayerImplementation<Parent>::next() |
640 | +{ |
641 | +} |
642 | + |
643 | +template<typename Parent> |
644 | +void media::ProxyPlayerImplementation<Parent>::previous() |
645 | +{ |
646 | +} |
647 | + |
648 | +template<typename Parent> |
649 | +void media::ProxyPlayerImplementation<Parent>::play() |
650 | +{ |
651 | + d->change_state(media::Player::playing); |
652 | +} |
653 | + |
654 | +template<typename Parent> |
655 | +void media::ProxyPlayerImplementation<Parent>::pause() |
656 | +{ |
657 | + d->change_state(media::Player::paused); |
658 | +} |
659 | + |
660 | +template<typename Parent> |
661 | +void media::ProxyPlayerImplementation<Parent>::stop() |
662 | +{ |
663 | + d->change_state(media::Player::stopped); |
664 | +} |
665 | + |
666 | +template<typename Parent> |
667 | +void media::ProxyPlayerImplementation<Parent>::seek_to(const std::chrono::microseconds& /*ms*/) |
668 | +{ |
669 | +} |
670 | + |
671 | +template<typename Parent> |
672 | +const core::Signal<>& media::ProxyPlayerImplementation<Parent>::on_client_disconnected() const |
673 | +{ |
674 | + return d->on_client_disconnected; |
675 | +} |
676 | + |
677 | +template<typename Parent> |
678 | +void media::ProxyPlayerImplementation<Parent>::emit_playback_status_changed(const media::Player::PlaybackStatus &status) |
679 | +{ |
680 | + Parent::playback_status_changed()(status); |
681 | +} |
682 | + |
683 | +#include <core/media/player_skeleton.h> |
684 | + |
685 | +// For linking purposes, we have to make sure that we have all symbols included within the dso. |
686 | +template class media::ProxyPlayerImplementation<media::PlayerSkeleton>; |
687 | |
688 | === added file 'src/core/media/proxy_player_implementation.h' |
689 | --- src/core/media/proxy_player_implementation.h 1970-01-01 00:00:00 +0000 |
690 | +++ src/core/media/proxy_player_implementation.h 2016-08-03 01:04:26 +0000 |
691 | @@ -0,0 +1,90 @@ |
692 | +/* |
693 | + * Copyright © 2013-2015 Canonical Ltd. |
694 | + * |
695 | + * This program is free software: you can redistribute it and/or modify it |
696 | + * under the terms of the GNU Lesser General Public License version 3, |
697 | + * as published by the Free Software Foundation. |
698 | + * |
699 | + * This program is distributed in the hope that it will be useful, |
700 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
701 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
702 | + * GNU Lesser General Public License for more details. |
703 | + * |
704 | + * You should have received a copy of the GNU Lesser General Public License |
705 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
706 | + * |
707 | + * Authored by: Justin McPherson <justin.mcpherson@canonical.com> |
708 | + */ |
709 | + |
710 | +#ifndef CORE_UBUNTU_MANAGED_MEDIA_PLAYER_IMPLEMENTATION_H_ |
711 | +#define CORE_UBUNTU_MANAGED_MEDIA_PLAYER_IMPLEMENTATION_H_ |
712 | + |
713 | +#include <core/media/player.h> |
714 | + |
715 | +#include "apparmor/ubuntu.h" |
716 | +#include "client_death_observer.h" |
717 | +#include "power/state_controller.h" |
718 | + |
719 | +#include <memory> |
720 | + |
721 | +namespace core |
722 | +{ |
723 | +namespace ubuntu |
724 | +{ |
725 | +namespace media |
726 | +{ |
727 | +class Engine; |
728 | +class Service; |
729 | + |
730 | +template<typename Parent> |
731 | +class ProxyPlayerImplementation : public Parent |
732 | +{ |
733 | +public: |
734 | + // All creation time arguments go here |
735 | + struct Configuration |
736 | + { |
737 | + // All creation time configuration options of the Parent class. |
738 | + typename Parent::Configuration parent; |
739 | + // The unique key identifying the player instance. |
740 | + Player::PlayerKey key; |
741 | + // Functional dependencies |
742 | + ClientDeathObserver::Ptr client_death_observer; |
743 | + power::StateController::Ptr power_state_controller; |
744 | + }; |
745 | + |
746 | + ProxyPlayerImplementation(const Configuration& configuration); |
747 | + ~ProxyPlayerImplementation(); |
748 | + |
749 | + virtual std::string uuid() const; |
750 | + virtual void reconnect(); |
751 | + virtual void abandon(); |
752 | + |
753 | + virtual std::shared_ptr<TrackList> track_list(); |
754 | + virtual Player::PlayerKey key() const; |
755 | + virtual Player::PlayerType type() const; |
756 | + |
757 | + virtual video::Sink::Ptr create_gl_texture_video_sink(std::uint32_t texture_id); |
758 | + |
759 | + virtual bool open_uri(const Track::UriType& uri); |
760 | + virtual bool open_uri(const Track::UriType& uri, const Player::HeadersType& headers); |
761 | + virtual void next(); |
762 | + virtual void previous(); |
763 | + virtual void play(); |
764 | + virtual void pause(); |
765 | + virtual void stop(); |
766 | + virtual void seek_to(const std::chrono::microseconds& offset); |
767 | + |
768 | + const core::Signal<>& on_client_disconnected() const; |
769 | + |
770 | +protected: |
771 | + void emit_playback_status_changed(const Player::PlaybackStatus &status); |
772 | + |
773 | +private: |
774 | + struct Private; |
775 | + std::shared_ptr<Private> d; |
776 | +}; |
777 | + |
778 | +} |
779 | +} |
780 | +} |
781 | +#endif // CORE_UBUNTU_MANAGED_MEDIA_PLAYER_IMPLEMENTATION_H_ |
782 | |
783 | === modified file 'src/core/media/service_implementation.cpp' |
784 | --- src/core/media/service_implementation.cpp 2016-07-19 21:22:18 +0000 |
785 | +++ src/core/media/service_implementation.cpp 2016-08-03 01:04:26 +0000 |
786 | @@ -28,6 +28,7 @@ |
787 | #include "player_configuration.h" |
788 | #include "player_skeleton.h" |
789 | #include "player_implementation.h" |
790 | +#include "proxy_player_implementation.h" |
791 | #include "power/battery_observer.h" |
792 | #include "power/state_controller.h" |
793 | #include "recorder_observer.h" |
794 | @@ -180,12 +181,10 @@ |
795 | { |
796 | } |
797 | |
798 | -std::shared_ptr<media::Player> media::ServiceImplementation::create_session( |
799 | - const media::Player::Configuration& conf) |
800 | +template<template <typename> class ImplementationType> |
801 | +std::shared_ptr<media::Player> media::ServiceImplementation::configure_player(const media::Player::Configuration& conf) |
802 | { |
803 | - // Create a new Player |
804 | - auto player = std::make_shared<media::PlayerImplementation<media::PlayerSkeleton>> |
805 | - (media::PlayerImplementation<media::PlayerSkeleton>::Configuration |
806 | + typename ImplementationType<media::PlayerSkeleton>::Configuration mixed_config |
807 | { |
808 | // Derive a PlayerSkeleton-specific Configuration based on Player::Configuration |
809 | media::PlayerSkeleton::Configuration |
810 | @@ -200,7 +199,9 @@ |
811 | conf.key, |
812 | d->client_death_observer, |
813 | d->power_state_controller |
814 | - }); |
815 | + }; |
816 | + |
817 | + auto player = std::make_shared<ImplementationType<media::PlayerSkeleton>>(mixed_config); |
818 | |
819 | auto key = conf.key; |
820 | // *Note: on_client_disconnected() is called from a Binder thread context |
821 | @@ -233,6 +234,20 @@ |
822 | return player; |
823 | } |
824 | |
825 | +std::shared_ptr<media::Player> media::ServiceImplementation::create_session( |
826 | + const media::Player::Configuration& conf) |
827 | +{ |
828 | + switch (conf.type) { |
829 | + case media::Player::standard: |
830 | + return configure_player<media::PlayerImplementation>(conf); |
831 | + case media::Player::proxied: |
832 | + return configure_player<media::ProxyPlayerImplementation>(conf); |
833 | + } |
834 | + |
835 | + MH_WARNING("Unrecognized player type - creating standard type"); |
836 | + return configure_player<media::PlayerImplementation>(conf); |
837 | +} |
838 | + |
839 | void media::ServiceImplementation::detach_session(const std::string&, const media::Player::Configuration&) |
840 | { |
841 | // no impl |
842 | |
843 | === modified file 'src/core/media/service_implementation.h' |
844 | --- src/core/media/service_implementation.h 2016-07-14 19:36:51 +0000 |
845 | +++ src/core/media/service_implementation.h 2016-08-03 01:04:26 +0000 |
846 | @@ -59,6 +59,9 @@ |
847 | void resume_paused_multimedia_sessions(bool resume_video_sessions = true); |
848 | void resume_multimedia_session(); |
849 | |
850 | + template<template <typename> class ImplementationType> |
851 | + std::shared_ptr<media::Player> configure_player(const Player::Configuration& conf); |
852 | + |
853 | struct Private; |
854 | std::shared_ptr<Private> d; |
855 | }; |
856 | |
857 | === modified file 'src/core/media/service_skeleton.cpp' |
858 | --- src/core/media/service_skeleton.cpp 2016-07-19 21:22:18 +0000 |
859 | +++ src/core/media/service_skeleton.cpp 2016-08-03 01:04:26 +0000 |
860 | @@ -123,8 +123,12 @@ |
861 | media::Player::PlayerKey key{std::get<1>(session_info)}; |
862 | std::string uuid{std::get<2>(session_info)}; |
863 | |
864 | + media::Player::PlayerType type; |
865 | + msg->reader() >> type; |
866 | + |
867 | media::Player::Configuration config |
868 | { |
869 | + type, |
870 | key, |
871 | impl->access_bus(), |
872 | impl->access_service(), |
873 | @@ -356,6 +360,7 @@ |
874 | |
875 | media::Player::Configuration config |
876 | { |
877 | + Player::standard, |
878 | key, |
879 | impl->access_bus(), |
880 | impl->access_service(), |
881 | |
882 | === modified file 'src/core/media/service_stub.cpp' |
883 | --- src/core/media/service_stub.cpp 2016-07-19 21:06:59 +0000 |
884 | +++ src/core/media/service_stub.cpp 2016-08-03 01:04:26 +0000 |
885 | @@ -19,7 +19,9 @@ |
886 | #include "service_stub.h" |
887 | #include "service_traits.h" |
888 | |
889 | +#include "codec.h" |
890 | #include "player_stub.h" |
891 | +#include "player_configuration.h" |
892 | #include "the_session_bus.h" |
893 | |
894 | #include "mpris/service.h" |
895 | @@ -75,10 +77,10 @@ |
896 | worker.join(); |
897 | } |
898 | |
899 | -std::shared_ptr<media::Player> media::ServiceStub::create_session(const media::Player::Configuration&) |
900 | +std::shared_ptr<media::Player> media::ServiceStub::create_session(const media::Player::Configuration& config) |
901 | { |
902 | - const auto op = object->invoke_method_synchronously<mpris::Service::CreateSession, |
903 | - std::tuple<dbus::types::ObjectPath, std::string>>(); |
904 | + const auto op = d->object->invoke_method_synchronously<mpris::Service::CreateSession, |
905 | + std::tuple<dbus::types::ObjectPath, std::string>>(config.type); |
906 | |
907 | if (op.is_error()) |
908 | throw std::runtime_error("Problem creating session: " + op.error()); |
909 | @@ -88,7 +90,8 @@ |
910 | shared_from_this(), |
911 | access_service(), |
912 | access_service()->object_for_path(std::get<0>(op.value())), |
913 | - std::get<1>(op.value()) |
914 | + std::get<1>(op.value()), |
915 | + config.type |
916 | }); |
917 | } |
918 |
See suggested changes inline