Merge lp:~justinmcp/media-hub/proxy-player into lp:media-hub

Proposed by Justin McPherson
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
Reviewer Review Type Date Requested Status
Jim Hodapp (community) code Approve
PS Jenkins bot continuous-integration Needs Fixing
Santosh Pending
Review via email: mp+268862@code.launchpad.net

Commit message

Support for external media players managed by media-hub.

To post a comment you must log in.
Revision history for this message
Jim Hodapp (jhodapp) wrote :

See suggested changes inline

review: Needs Fixing (code)
Revision history for this message
Justin McPherson (justinmcp) :
Revision history for this message
Jim Hodapp (jhodapp) :
Revision history for this message
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://code.launchpad.net/~justinmcp/media-hub/proxy-player/+merge/268862/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/media-hub-ci/377/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/media-hub-vivid-amd64-ci/217/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/media-hub-vivid-armhf-ci/217/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/media-hub-vivid-i386-ci/217/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/media-hub-ci/377/rebuild

review: Needs Fixing (continuous-integration)
lp:~justinmcp/media-hub/proxy-player updated
156. By Justin McPherson

Merge from trunk.

Revision history for this message
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://code.launchpad.net/~justinmcp/media-hub/proxy-player/+merge/268862/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/media-hub-ci/404/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/media-hub-vivid-amd64-ci/244
    SUCCESS: http://jenkins.qa.ubuntu.com/job/media-hub-vivid-armhf-ci/244
        deb: http://jenkins.qa.ubuntu.com/job/media-hub-vivid-armhf-ci/244/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/media-hub-vivid-i386-ci/244

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/media-hub-ci/404/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Jim Hodapp (jhodapp) :
Revision history for this message
Justin McPherson (justinmcp) :
Revision history for this message
Jim Hodapp (jhodapp) :
Revision history for this message
Justin McPherson (justinmcp) :
Revision history for this message
Jim Hodapp (jhodapp) :
Revision history for this message
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.

review: Needs Fixing (code)
lp:~justinmcp/media-hub/proxy-player updated
157. By Justin McPherson

Enable variant session type through the Player Configuration structure.

Revision history for this message
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.

Revision history for this message
Justin McPherson (justinmcp) :
Revision history for this message
Justin McPherson (justinmcp) :
Revision history for this message
Jim Hodapp (jhodapp) :
Revision history for this message
Justin McPherson (justinmcp) :
lp:~justinmcp/media-hub/proxy-player updated
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

Revision history for this message
Jim Hodapp (jhodapp) :
Revision history for this message
Jim Hodapp (jhodapp) wrote :

Also I was curious how you've been testing this out? Does it already link to Oxide in some way?

Revision history for this message
Justin McPherson (justinmcp) wrote :

Sometime ago, this branch was working with https://code.launchpad.net/~justinmcp/oxide/media-arbitration.

lp:~justinmcp/media-hub/proxy-player updated
161. By Justin McPherson

Rename PlayerType enum values.

rigged -> standard
proxy -> proxied

162. By Justin McPherson

Renable test

163. By Justin McPherson

Changelog entry

Revision history for this message
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.

review: Needs Fixing
lp:~justinmcp/media-hub/proxy-player updated
164. By Justin McPherson

Remove entry

Revision history for this message
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.

lp:~justinmcp/media-hub/proxy-player updated
165. By Justin McPherson

Fix changelog

Revision history for this message
Justin McPherson (justinmcp) wrote :

Before my morning coffee, apologies, the latter was meant, the former was done. Fixed...

Revision history for this message
Jim Hodapp (jhodapp) wrote :

LGTM

review: Approve (code)
lp:~justinmcp/media-hub/proxy-player updated
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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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

Subscribers

People subscribed via source and target branches