Merge lp:~ricmm/media-hub/session-reattach-nonfixed into lp:media-hub

Proposed by Ricardo Mendoza
Status: Merged
Approved by: Jim Hodapp
Approved revision: 155
Merged at revision: 133
Proposed branch: lp:~ricmm/media-hub/session-reattach-nonfixed
Merge into: lp:media-hub
Prerequisite: lp:~phablet-team/media-hub/tracklist-cli
Diff against target: 1135 lines (+555/-61)
19 files modified
CMakeLists.txt (+1/-1)
debian/changelog (+6/-0)
include/core/media/player.h (+4/-0)
include/core/media/service.h (+16/-0)
src/core/media/mpris/service.h (+39/-0)
src/core/media/player_configuration.h (+1/-1)
src/core/media/player_implementation.cpp (+47/-17)
src/core/media/player_implementation.h (+4/-0)
src/core/media/player_stub.cpp (+22/-3)
src/core/media/player_stub.h (+6/-1)
src/core/media/server/server.cpp (+1/-1)
src/core/media/service_implementation.cpp (+16/-0)
src/core/media/service_implementation.h (+3/-0)
src/core/media/service_skeleton.cpp (+235/-12)
src/core/media/service_skeleton.h (+6/-0)
src/core/media/service_stub.cpp (+39/-3)
src/core/media/service_stub.h (+3/-0)
tests/test-track-list/test_track_list.cpp (+99/-20)
tests/test-track-list/test_track_list.h (+7/-2)
To merge this branch: bzr merge lp:~ricmm/media-hub/session-reattach-nonfixed
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Thomas Voß (community) Approve
Jim Hodapp (community) code Approve
Review via email: mp+256101@code.launchpad.net

This proposal supersedes a proposal from 2015-04-10.

Commit message

Player session attaching/detaching with UUID

Description of the change

Player session attaching/detaching with UUID

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:139
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/~ricmm/media-hub/session-reattach-nonfixed/+merge/256101/+edit-commit-message

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

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Jim Hodapp (jhodapp) wrote :

Looks good, a few things to fix.

review: Needs Fixing (code)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Jim Hodapp (jhodapp) wrote :

Looks good, thanks.

review: Approve (code)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
141. By Ricardo Mendoza

Merge parent

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Thomas Voß (thomas-voss) wrote :

A few comments inline, one bigger question:

What is the difference between reattach/detach and the existing resume_session functionality?

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

Some added comments to my review and tvoss' review.

Revision history for this message
Thomas Voß (thomas-voss) wrote :

Replied inline.

Revision history for this message
Jim Hodapp (jhodapp) :
142. By Ricardo Mendoza

Address review comments and plug through no-impl methods of the Service parts

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
143. By Ricardo Mendoza

Not a reference

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
144. By Ricardo Mendoza

Correctly propagate track list changes from bus to local and viceversa

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Thomas Voß (thomas-voss) wrote :
Download full text (33.8 KiB)

On Thu, Apr 16, 2015 at 5:14 PM, Jim Hodapp <email address hidden> wrote:
>
>
> Diff comments:
>
>> === modified file 'CMakeLists.txt'
>> --- CMakeLists.txt 2015-01-23 13:00:36 +0000
>> +++ CMakeLists.txt 2015-04-15 18:29:47 +0000
>> @@ -3,7 +3,7 @@
>> project(ubuntu-media-hub)
>>
>> set(UBUNTU_MEDIA_HUB_VERSION_MAJOR 3)
>> -set(UBUNTU_MEDIA_HUB_VERSION_MINOR 0)
>> +set(UBUNTU_MEDIA_HUB_VERSION_MINOR 1)
>> set(UBUNTU_MEDIA_HUB_VERSION_PATCH 0)
>>
>> set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -fPIC -pthread")
>>
>> === modified file 'debian/changelog'
>> --- debian/changelog 2015-04-02 16:43:42 +0000
>> +++ debian/changelog 2015-04-15 18:29:47 +0000
>> @@ -1,3 +1,9 @@
>> +media-hub (3.1.0) UNRELEASED; urgency=medium
>> +
>> + * Support for signalling player reconnection up the stack.
>> +
>> + -- Ricardo Mendoza <email address hidden> Fri, 10 Apr 2015 18:20:32 +0200
>> +
>> media-hub (3.0.0+15.04.20150402-0ubuntu1) vivid; urgency=medium
>>
>> [ Jim Hodapp ]
>>
>> === modified file 'include/core/media/player.h'
>> --- include/core/media/player.h 2015-04-15 18:29:47 +0000
>> +++ include/core/media/player.h 2015-04-15 18:29:47 +0000
>> @@ -126,6 +126,9 @@
>> Player& operator=(const Player&) = delete;
>> bool operator==(const Player&) const = delete;
>>
>> + virtual std::string uuid() const = 0;
>
> Yeah I would say this isn't hugely important though as the likely-hood of this happening is very slim. Also, we could just change it if that unlikely event occurred.
>

That's somewhat difficult as this is public facing API. Your call.

>> + virtual void reconnect() = 0;
>> +
>> virtual std::shared_ptr<TrackList> track_list() = 0;
>> virtual PlayerKey key() const = 0;
>>
>>
>> === modified file 'include/core/media/service.h'
>> --- include/core/media/service.h 2014-09-30 06:51:15 +0000
>> +++ include/core/media/service.h 2015-04-15 18:29:47 +0000
>> @@ -42,9 +42,25 @@
>> Service& operator=(const Service&) = delete;
>> bool operator==(const Service&) const = delete;
>>
>> + /** @brief Creates a session with the media-hub service. */
>> virtual std::shared_ptr<Player> create_session(const Player::Configuration&) = 0;
>> +
>> + /** @brief Detaches a UUID-identified session for later resuming. */
>> + virtual void detach_session(const std::string& uuid, const Player::Configuration&) = 0;
>> +
>> + /** @brief Reattaches to a UUID-identified session that is in detached state. */
>> + virtual std::shared_ptr<Player> reattach_session(const std::string& uuid, const Player::Configuration&) = 0;
>> +
>> + /** @brief Asks the service to destroy a session. The session is destroyed when the client exits. */
>> + virtual void destroy_session(const std::string& uuid, const Player::Configuration&) = 0;
>> +
>> + /** @brief Creates a fixed-named session with the media-hub service. */
>> virtual std::shared_ptr<Player> create_fixed_session(const std::string& name, const Player::Configuration&) = 0;
>> +
>> + /** @brief Resumes a fixed-name session directly by player key. */
>> virtual std::shared_ptr<Player> resume_session(Player::Play...

145. By Ricardo Mendoza

Remove printfs

Revision history for this message
Thomas Voß (thomas-voss) wrote :

LGTM.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
146. By Ricardo Mendoza

Revert last changes

147. By Ricardo Mendoza

Delete player instance instead of abandoning

148. By Ricardo Mendoza

Update tracklist cli for new api

149. By Ricardo Mendoza

Merge parent

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
150. By Ricardo Mendoza

Implement full player destruction

151. By Ricardo Mendoza

Merge parent

152. By Ricardo Mendoza

Syntax error

153. By Ricardo Mendoza

Sync test cli

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
154. By Ricardo Mendoza

Merge parent

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
155. By Ricardo Mendoza

Merge parent

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)

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 2015-01-23 13:00:36 +0000
3+++ CMakeLists.txt 2015-04-20 15:56:34 +0000
4@@ -3,7 +3,7 @@
5 project(ubuntu-media-hub)
6
7 set(UBUNTU_MEDIA_HUB_VERSION_MAJOR 3)
8-set(UBUNTU_MEDIA_HUB_VERSION_MINOR 0)
9+set(UBUNTU_MEDIA_HUB_VERSION_MINOR 1)
10 set(UBUNTU_MEDIA_HUB_VERSION_PATCH 0)
11
12 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -fPIC -pthread")
13
14=== modified file 'debian/changelog'
15--- debian/changelog 2015-04-02 16:43:42 +0000
16+++ debian/changelog 2015-04-20 15:56:34 +0000
17@@ -1,3 +1,9 @@
18+media-hub (3.1.0) UNRELEASED; urgency=medium
19+
20+ * Support for signalling player reconnection up the stack.
21+
22+ -- Ricardo Mendoza <ricardo.mendoza@canonical.com> Fri, 10 Apr 2015 18:20:32 +0200
23+
24 media-hub (3.0.0+15.04.20150402-0ubuntu1) vivid; urgency=medium
25
26 [ Jim Hodapp ]
27
28=== modified file 'include/core/media/player.h'
29--- include/core/media/player.h 2015-04-20 15:56:34 +0000
30+++ include/core/media/player.h 2015-04-20 15:56:34 +0000
31@@ -126,6 +126,10 @@
32 Player& operator=(const Player&) = delete;
33 bool operator==(const Player&) const = delete;
34
35+ virtual std::string uuid() const = 0;
36+ virtual void reconnect() = 0;
37+ virtual void abandon() = 0;
38+
39 virtual std::shared_ptr<TrackList> track_list() = 0;
40 virtual PlayerKey key() const = 0;
41
42
43=== modified file 'include/core/media/service.h'
44--- include/core/media/service.h 2014-09-30 06:51:15 +0000
45+++ include/core/media/service.h 2015-04-20 15:56:34 +0000
46@@ -42,9 +42,25 @@
47 Service& operator=(const Service&) = delete;
48 bool operator==(const Service&) const = delete;
49
50+ /** @brief Creates a session with the media-hub service. */
51 virtual std::shared_ptr<Player> create_session(const Player::Configuration&) = 0;
52+
53+ /** @brief Detaches a UUID-identified session for later resuming. */
54+ virtual void detach_session(const std::string& uuid, const Player::Configuration&) = 0;
55+
56+ /** @brief Reattaches to a UUID-identified session that is in detached state. */
57+ virtual std::shared_ptr<Player> reattach_session(const std::string& uuid, const Player::Configuration&) = 0;
58+
59+ /** @brief Asks the service to destroy a session. The session is destroyed when the client exits. */
60+ virtual void destroy_session(const std::string& uuid, const Player::Configuration&) = 0;
61+
62+ /** @brief Creates a fixed-named session with the media-hub service. */
63 virtual std::shared_ptr<Player> create_fixed_session(const std::string& name, const Player::Configuration&) = 0;
64+
65+ /** @brief Resumes a fixed-name session directly by player key. */
66 virtual std::shared_ptr<Player> resume_session(Player::PlayerKey) = 0;
67+
68+ /** @brief Pauses sessions other than the supplied one. */
69 virtual void pause_other_sessions(Player::PlayerKey) = 0;
70
71 protected:
72
73=== modified file 'src/core/media/mpris/service.h'
74--- src/core/media/mpris/service.h 2014-09-30 06:51:15 +0000
75+++ src/core/media/mpris/service.h 2015-04-20 15:56:34 +0000
76@@ -48,6 +48,42 @@
77 }
78 };
79
80+ struct DetachingSession
81+ {
82+ static const std::string& name()
83+ {
84+ static const std::string s
85+ {
86+ "core.ubuntu.media.Service.Error.DetachingSession"
87+ };
88+ return s;
89+ }
90+ };
91+
92+ struct ReattachingSession
93+ {
94+ static const std::string& name()
95+ {
96+ static const std::string s
97+ {
98+ "core.ubuntu.media.Service.Error.ReattachingSession"
99+ };
100+ return s;
101+ }
102+ };
103+
104+ struct DestroyingSession
105+ {
106+ static const std::string& name()
107+ {
108+ static const std::string s
109+ {
110+ "core.ubuntu.media.Service.Error.DestroyingSession"
111+ };
112+ return s;
113+ }
114+ };
115+
116 struct CreatingFixedSession
117 {
118 static const std::string& name()
119@@ -74,6 +110,9 @@
120 };
121
122 DBUS_CPP_METHOD_WITH_TIMEOUT_DEF(CreateSession, Service, 1000)
123+ DBUS_CPP_METHOD_WITH_TIMEOUT_DEF(DetachSession, Service, 1000)
124+ DBUS_CPP_METHOD_WITH_TIMEOUT_DEF(ReattachSession, Service, 1000)
125+ DBUS_CPP_METHOD_WITH_TIMEOUT_DEF(DestroySession, Service, 1000)
126 DBUS_CPP_METHOD_WITH_TIMEOUT_DEF(CreateFixedSession, Service, 1000)
127 DBUS_CPP_METHOD_WITH_TIMEOUT_DEF(ResumeSession, Service, 1000)
128 DBUS_CPP_METHOD_WITH_TIMEOUT_DEF(PauseOtherSessions, Service, 1000)
129
130=== modified file 'src/core/media/player_configuration.h'
131--- src/core/media/player_configuration.h 2015-04-20 15:56:34 +0000
132+++ src/core/media/player_configuration.h 2015-04-20 15:56:34 +0000
133@@ -27,7 +27,7 @@
134 // to the implementation in a way that is opaque to the client.
135 struct core::ubuntu::media::Player::Configuration
136 {
137- // Unique key for identifying the session.
138+ // Unique key for identifying the session path.
139 core::ubuntu::media::Player::PlayerKey key;
140 // The bus connection to expose objects on.
141 std::shared_ptr<core::dbus::Bus> bus;
142
143=== modified file 'src/core/media/player_implementation.cpp'
144--- src/core/media/player_implementation.cpp 2015-04-20 15:56:34 +0000
145+++ src/core/media/player_implementation.cpp 2015-04-20 15:56:34 +0000
146@@ -68,7 +68,7 @@
147 previous_state(Engine::State::stopped),
148 engine_state_change_connection(engine->state().changed().connect(make_state_change_handler())),
149 engine_playback_status_change_connection(engine->playback_status_changed_signal().connect(make_playback_status_change_handler())),
150- doing_go_to_track(false)
151+ doing_abandon(false)
152 {
153 // Poor man's logging of release/acquire events.
154 display_state_lock->acquired().connect([](media::power::DisplayState state)
155@@ -301,7 +301,8 @@
156 core::Connection engine_state_change_connection;
157 core::Connection engine_playback_status_change_connection;
158 // Prevent the TrackList from auto advancing to the next track
159- std::atomic<bool> doing_go_to_track;
160+ std::mutex doing_go_to_track;
161+ std::atomic<bool> doing_abandon;
162 };
163
164 template<typename Parent>
165@@ -390,23 +391,26 @@
166
167 d->engine->about_to_finish_signal().connect([this]()
168 {
169+ if (d->doing_abandon)
170+ return;
171+
172 Parent::about_to_finish()();
173
174- if (!d->doing_go_to_track)
175+ // This lambda needs to be mutually exclusive with the on_go_to_track lambda below
176+ d->doing_go_to_track.lock();
177+
178+ const media::Track::Id prev_track_id = d->track_list->current();
179+ // Make sure that the TrackList keeps advancing. The logic for what gets played next,
180+ // if anything at all, occurs in TrackListSkeleton::next()
181+ const Track::UriType uri = d->track_list->query_uri_for_track(d->track_list->next());
182+ if (prev_track_id != d->track_list->current() && !uri.empty())
183 {
184- const media::Track::Id prev_track_id = d->track_list->current();
185- // Make sure that the TrackList keeps advancing. The logic for what gets played next,
186- // if anything at all, occurs in TrackListSkeleton::next()
187- const Track::UriType uri = d->track_list->query_uri_for_track(d->track_list->next());
188- if (prev_track_id != d->track_list->current() && !uri.empty())
189- {
190- std::cout << "Setting next track on playbin: " << uri << std::endl;
191- static const bool do_pipeline_reset = false;
192- d->engine->open_resource_for_uri(uri, do_pipeline_reset);
193- }
194+ std::cout << "Setting next track on playbin: " << uri << std::endl;
195+ static const bool do_pipeline_reset = false;
196+ d->engine->open_resource_for_uri(uri, do_pipeline_reset);
197 }
198- else
199- std::cout << "Not auto-advancing the TrackList since doing_go_to_track is true" << std::endl;
200+
201+ d->doing_go_to_track.unlock();
202 });
203
204 d->engine->client_disconnected_signal().connect([this]()
205@@ -443,7 +447,8 @@
206 {
207 // This prevents the TrackList from auto advancing in other areas such as the about_to_finish signal
208 // handler.
209- d->doing_go_to_track = true;
210+ // This lambda needs to be mutually exclusive with the about_to_finish lambda above
211+ d->doing_go_to_track.lock();
212
213 const media::Track::Id id = p.first;
214 const bool toggle_player_state = p.second;
215@@ -463,7 +468,8 @@
216 if (toggle_player_state)
217 d->engine->play();
218
219- d->doing_go_to_track = false;
220+ d->doing_go_to_track.unlock();
221+
222 });
223
224 // Everything is setup, we now subscribe to death notifications.
225@@ -474,6 +480,9 @@
226 {
227 if (auto sp = wp.lock())
228 {
229+ if (sp->doing_abandon)
230+ return;
231+
232 if (died != sp->config.key)
233 return;
234
235@@ -519,6 +528,27 @@
236 }
237
238 template<typename Parent>
239+std::string media::PlayerImplementation<Parent>::uuid() const
240+{
241+ // No impl for now, as not needed internally.
242+ return std::string{};
243+}
244+
245+template<typename Parent>
246+void media::PlayerImplementation<Parent>::reconnect()
247+{
248+ d->config.client_death_observer->register_for_death_notifications_with_key(d->config.key);
249+}
250+
251+template<typename Parent>
252+void media::PlayerImplementation<Parent>::abandon()
253+{
254+ // Signal client disconnection due to abandonment of player
255+ d->doing_abandon = true;
256+ d->on_client_died();
257+}
258+
259+template<typename Parent>
260 std::shared_ptr<media::TrackList> media::PlayerImplementation<Parent>::track_list()
261 {
262 return d->track_list;
263
264=== modified file 'src/core/media/player_implementation.h'
265--- src/core/media/player_implementation.h 2015-04-20 15:56:34 +0000
266+++ src/core/media/player_implementation.h 2015-04-20 15:56:34 +0000
267@@ -55,6 +55,10 @@
268 PlayerImplementation(const Configuration& configuration);
269 ~PlayerImplementation();
270
271+ virtual std::string uuid() const;
272+ virtual void reconnect();
273+ virtual void abandon();
274+
275 virtual std::shared_ptr<TrackList> track_list();
276 virtual Player::PlayerKey key() const;
277
278
279=== modified file 'src/core/media/player_stub.cpp'
280--- src/core/media/player_stub.cpp 2015-04-20 15:56:34 +0000
281+++ src/core/media/player_stub.cpp 2015-04-20 15:56:34 +0000
282@@ -44,11 +44,13 @@
283 {
284 Private(const std::shared_ptr<Service>& parent,
285 const std::shared_ptr<core::dbus::Service>& service,
286- const std::shared_ptr<core::dbus::Object>& object
287+ const std::shared_ptr<core::dbus::Object>& object,
288+ const std::string& uuid
289 ) : parent(parent),
290 service(service),
291 object(object),
292 key(object->invoke_method_synchronously<mpris::Player::Key, media::Player::PlayerKey>().value()),
293+ uuid(uuid),
294 sink_factory(media::video::make_platform_default_sink_factory(key)),
295 properties
296 {
297@@ -96,6 +98,7 @@
298 dbus::Service::Ptr service;
299 dbus::Object::Ptr object;
300 media::Player::PlayerKey key;
301+ std::string uuid;
302 media::video::SinkFactory sink_factory;
303 struct
304 {
305@@ -213,8 +216,9 @@
306 media::PlayerStub::PlayerStub(
307 const std::shared_ptr<Service>& parent,
308 const std::shared_ptr<core::dbus::Service>& service,
309- const std::shared_ptr<core::dbus::Object>& object)
310- : d(new Private{parent, service, object})
311+ const std::shared_ptr<core::dbus::Object>& object,
312+ const std::string& uuid)
313+ : d(new Private{parent, service, object, uuid})
314 {
315 }
316
317@@ -222,6 +226,21 @@
318 {
319 }
320
321+std::string media::PlayerStub::uuid() const
322+{
323+ return d->uuid;
324+}
325+
326+void media::PlayerStub::reconnect()
327+{
328+ // No implementation
329+}
330+
331+void media::PlayerStub::abandon()
332+{
333+ // No implementation
334+}
335+
336 std::shared_ptr<media::TrackList> media::PlayerStub::track_list()
337 {
338 if (!d->track_list)
339
340=== modified file 'src/core/media/player_stub.h'
341--- src/core/media/player_stub.h 2015-04-20 15:56:34 +0000
342+++ src/core/media/player_stub.h 2015-04-20 15:56:34 +0000
343@@ -40,10 +40,15 @@
344 explicit PlayerStub(
345 const std::shared_ptr<Service>& parent,
346 const std::shared_ptr<core::dbus::Service>& service,
347- const std::shared_ptr<core::dbus::Object>& object);
348+ const std::shared_ptr<core::dbus::Object>& object,
349+ const std::string& uuid = std::string{});
350
351 ~PlayerStub();
352
353+ virtual std::string uuid() const;
354+ virtual void reconnect();
355+ virtual void abandon();
356+
357 virtual std::shared_ptr<TrackList> track_list();
358 virtual PlayerKey key() const;
359
360
361=== modified file 'src/core/media/server/server.cpp'
362--- src/core/media/server/server.cpp 2014-12-15 14:43:44 +0000
363+++ src/core/media/server/server.cpp 2015-04-20 15:56:34 +0000
364@@ -123,7 +123,7 @@
365 {
366 impl,
367 player_store,
368-
369+ external_services
370 });
371
372 std::thread service_worker
373
374=== modified file 'src/core/media/service_implementation.cpp'
375--- src/core/media/service_implementation.cpp 2015-04-20 15:56:34 +0000
376+++ src/core/media/service_implementation.cpp 2015-04-20 15:56:34 +0000
377@@ -218,6 +218,22 @@
378 return player;
379 }
380
381+void media::ServiceImplementation::detach_session(const std::string&, const media::Player::Configuration&)
382+{
383+ // no impl
384+}
385+
386+std::shared_ptr<media::Player> media::ServiceImplementation::reattach_session(const std::string&, const media::Player::Configuration&)
387+{
388+ // no impl
389+ return std::shared_ptr<media::Player>();
390+}
391+
392+void media::ServiceImplementation::destroy_session(const std::string&, const media::Player::Configuration&)
393+{
394+ // no impl
395+}
396+
397 std::shared_ptr<media::Player> media::ServiceImplementation::create_fixed_session(const std::string&, const media::Player::Configuration&)
398 {
399 // no impl
400
401=== modified file 'src/core/media/service_implementation.h'
402--- src/core/media/service_implementation.h 2015-04-02 14:46:52 +0000
403+++ src/core/media/service_implementation.h 2015-04-20 15:56:34 +0000
404@@ -44,6 +44,9 @@
405 ~ServiceImplementation ();
406
407 std::shared_ptr<Player> create_session(const Player::Configuration&);
408+ void detach_session(const std::string&, const Player::Configuration&);
409+ std::shared_ptr<Player> reattach_session(const std::string&, const Player::Configuration&);
410+ void destroy_session(const std::string&, const Player::Configuration&);
411 std::shared_ptr<Player> create_fixed_session(const std::string& name, const Player::Configuration&);
412 std::shared_ptr<Player> resume_session(Player::PlayerKey key);
413 void pause_other_sessions(Player::PlayerKey key);
414
415=== modified file 'src/core/media/service_skeleton.cpp'
416--- src/core/media/service_skeleton.cpp 2015-04-20 15:56:34 +0000
417+++ src/core/media/service_skeleton.cpp 2015-04-20 15:56:34 +0000
418@@ -35,6 +35,10 @@
419
420 #include <core/posix/this_process.h>
421
422+#include <boost/uuid/uuid.hpp>
423+#include <boost/uuid/uuid_generators.hpp>
424+#include <boost/uuid/uuid_io.hpp>
425+
426 #include <map>
427 #include <regex>
428 #include <sstream>
429@@ -50,17 +54,33 @@
430 struct media::ServiceSkeleton::Private
431 {
432 Private(media::ServiceSkeleton* impl, const ServiceSkeleton::Configuration& config)
433- : impl(impl),
434+ : request_context_resolver(media::apparmor::ubuntu::make_platform_default_request_context_resolver(config.external_services)),
435+ impl(impl),
436 object(impl->access_service()->add_object_for_path(
437 dbus::traits::Service<media::Service>::object_path())),
438- exported(impl->access_bus(), config.cover_art_resolver),
439- configuration(config)
440+ configuration(config),
441+ exported(impl->access_bus(), config.cover_art_resolver)
442 {
443 object->install_method_handler<mpris::Service::CreateSession>(
444 std::bind(
445 &Private::handle_create_session,
446 this,
447 std::placeholders::_1));
448+ object->install_method_handler<mpris::Service::DetachSession>(
449+ std::bind(
450+ &Private::handle_detach_session,
451+ this,
452+ std::placeholders::_1));
453+ object->install_method_handler<mpris::Service::ReattachSession>(
454+ std::bind(
455+ &Private::handle_reattach_session,
456+ this,
457+ std::placeholders::_1));
458+ object->install_method_handler<mpris::Service::DestroySession>(
459+ std::bind(
460+ &Private::handle_destroy_session,
461+ this,
462+ std::placeholders::_1));
463 object->install_method_handler<mpris::Service::CreateFixedSession>(
464 std::bind(
465 &Private::handle_create_fixed_session,
466@@ -78,24 +98,26 @@
467 std::placeholders::_1));
468 }
469
470- std::pair<std::string, media::Player::PlayerKey> create_session_info()
471+ std::tuple<std::string, media::Player::PlayerKey, std::string> create_session_info()
472 {
473 static unsigned int session_counter = 0;
474
475 unsigned int current_session = session_counter++;
476+ boost::uuids::uuid uuid = gen();
477
478 std::stringstream ss;
479 ss << "/core/ubuntu/media/Service/sessions/" << current_session;
480
481- return std::make_pair(ss.str(), media::Player::PlayerKey(current_session));
482+ return std::make_tuple(ss.str(), media::Player::PlayerKey(current_session), to_string(uuid));
483 }
484
485 void handle_create_session(const core::dbus::Message::Ptr& msg)
486 {
487- auto session_info = create_session_info();
488+ auto session_info = create_session_info();
489
490- dbus::types::ObjectPath op{session_info.first};
491- media::Player::PlayerKey key{session_info.second};
492+ dbus::types::ObjectPath op{std::get<0>(session_info)};
493+ media::Player::PlayerKey key{std::get<1>(session_info)};
494+ std::string uuid{std::get<2>(session_info)};
495
496 media::Player::Configuration config
497 {
498@@ -105,11 +127,21 @@
499 impl->access_service()->add_object_for_path(op)
500 };
501
502+ std::cout << "Session created by request of: " << msg->sender() << ", uuid: " << uuid << ", path:" << op << std::endl;
503+
504 try
505 {
506 configuration.player_store->add_player_for_key(key, impl->create_session(config));
507+ uuid_player_map.insert(std::make_pair(uuid, key));
508+
509+ request_context_resolver->resolve_context_for_dbus_name_async(msg->sender(), [this, key, msg](const media::apparmor::ubuntu::Context& context)
510+ {
511+ fprintf(stderr, "%s():%d -- app_name='%s', attached\n", __func__, __LINE__, context.str().c_str());
512+ player_owner_map.insert(std::make_pair(key, std::make_tuple(context.str(), true, msg->sender())));
513+ });
514+
515 auto reply = dbus::Message::make_method_return(msg);
516- reply->writer() << op;
517+ reply->writer() << std::make_tuple(op, uuid);
518
519 impl->access_bus()->send(reply);
520 } catch(const std::runtime_error& e)
521@@ -122,6 +154,174 @@
522 }
523 }
524
525+ void handle_detach_session(const core::dbus::Message::Ptr& msg)
526+ {
527+ try
528+ {
529+ std::string uuid;
530+ msg->reader() >> uuid;
531+
532+ auto key = uuid_player_map.at(uuid);
533+
534+ if (player_owner_map.count(key) != 0) {
535+ auto info = player_owner_map.at(key);
536+ // Check if session is attached(1) and that the detachment
537+ // request comes from the same peer(2) that created the session.
538+ if (std::get<1>(info) && (std::get<2>(info) == msg->sender())) { // Player is attached
539+ std::get<1>(info) = false; // Detached
540+ std::get<2>(info).clear(); // Clear registered sender/peer
541+ auto player = configuration.player_store->player_for_key(key);
542+ player->lifetime().set(media::Player::Lifetime::resumable);
543+ }
544+ }
545+
546+ auto reply = dbus::Message::make_method_return(msg);
547+ impl->access_bus()->send(reply);
548+
549+ } catch(const std::runtime_error& e)
550+ {
551+ auto reply = dbus::Message::make_error(
552+ msg,
553+ mpris::Service::Errors::DetachingSession::name(),
554+ e.what());
555+ impl->access_bus()->send(reply);
556+ }
557+ }
558+
559+ void handle_reattach_session(const core::dbus::Message::Ptr& msg)
560+ {
561+ try
562+ {
563+ std::string uuid;
564+ msg->reader() >> uuid;
565+
566+ if (uuid_player_map.count(uuid) != 0) {
567+ auto key = uuid_player_map.at(uuid);
568+ if (not configuration.player_store->has_player_for_key(key)) {
569+ auto reply = dbus::Message::make_error(
570+ msg,
571+ mpris::Service::Errors::ReattachingSession::name(),
572+ "Unable to locate player session");
573+ impl->access_bus()->send(reply);
574+ return;
575+ }
576+ std::stringstream ss;
577+ ss << "/core/ubuntu/media/Service/sessions/" << key;
578+ dbus::types::ObjectPath op{ss.str()};
579+
580+ request_context_resolver->resolve_context_for_dbus_name_async(msg->sender(), [this, msg, key, op](const media::apparmor::ubuntu::Context& context)
581+ {
582+ auto info = player_owner_map.at(key);
583+ fprintf(stderr, "%s():%d -- reattach app_name='%s', info='%s', '%s'\n", __func__, __LINE__, context.str().c_str(), std::get<0>(info).c_str(), std::get<2>(info).c_str());
584+ if (std::get<0>(info) == context.str()) {
585+ std::get<1>(info) = true; // Set to Attached
586+ std::get<2>(info) = msg->sender(); // Register new owner
587+
588+ // Signal player reconnection
589+ auto player = configuration.player_store->player_for_key(key);
590+ player->reconnect();
591+
592+ auto reply = dbus::Message::make_method_return(msg);
593+ reply->writer() << op;
594+
595+ impl->access_bus()->send(reply);
596+ }
597+ else {
598+ auto reply = dbus::Message::make_error(
599+ msg,
600+ mpris::Service::Errors::ReattachingSession::name(),
601+ "Invalid permissions for the requested session");
602+ impl->access_bus()->send(reply);
603+ return;
604+ }
605+ });
606+ }
607+ else {
608+ auto reply = dbus::Message::make_error(
609+ msg,
610+ mpris::Service::Errors::ReattachingSession::name(),
611+ "Invalid session");
612+ impl->access_bus()->send(reply);
613+ return;
614+ }
615+ } catch(const std::runtime_error& e)
616+ {
617+ auto reply = dbus::Message::make_error(
618+ msg,
619+ mpris::Service::Errors::ReattachingSession::name(),
620+ e.what());
621+ impl->access_bus()->send(reply);
622+ }
623+ }
624+
625+ void handle_destroy_session(const core::dbus::Message::Ptr& msg)
626+ {
627+
628+ try
629+ {
630+ std::string uuid;
631+ msg->reader() >> uuid;
632+
633+ if (uuid_player_map.count(uuid) != 0) {
634+ auto key = uuid_player_map.at(uuid);
635+ if (not configuration.player_store->has_player_for_key(key)) {
636+ auto reply = dbus::Message::make_error(
637+ msg,
638+ mpris::Service::Errors::DestroyingSession::name(),
639+ "Unable to locate player session");
640+ impl->access_bus()->send(reply);
641+ return;
642+ }
643+
644+ // Remove control entries from the map, at this point
645+ // the session is no longer usable.
646+ uuid_player_map.erase(uuid);
647+
648+ request_context_resolver->resolve_context_for_dbus_name_async(msg->sender(), [this, msg, key](const media::apparmor::ubuntu::Context& context)
649+ {
650+ auto info = player_owner_map.at(key);
651+ fprintf(stderr, "%s():%d -- Destroying app_name='%s', info='%s', '%s'\n", __func__, __LINE__, context.str().c_str(), std::get<0>(info).c_str(), std::get<2>(info).c_str());
652+ if (std::get<0>(info) == context.str()) {
653+ player_owner_map.erase(key);
654+
655+ // Reset lifecycle to non-resumable on the now-abandoned session
656+ auto player = configuration.player_store->player_for_key(key);
657+
658+ // Delete player instance by abandonment
659+ player->lifetime().set(media::Player::Lifetime::normal);
660+ player->abandon();
661+
662+ auto reply = dbus::Message::make_method_return(msg);
663+ impl->access_bus()->send(reply);
664+ }
665+ else {
666+ auto reply = dbus::Message::make_error(
667+ msg,
668+ mpris::Service::Errors::DestroyingSession::name(),
669+ "Invalid permissions for the requested session");
670+ impl->access_bus()->send(reply);
671+ return;
672+ }
673+ });
674+ }
675+ else {
676+ auto reply = dbus::Message::make_error(
677+ msg,
678+ mpris::Service::Errors::DestroyingSession::name(),
679+ "Invalid session");
680+ impl->access_bus()->send(reply);
681+ return;
682+ }
683+ } catch(const std::runtime_error& e)
684+ {
685+ auto reply = dbus::Message::make_error(
686+ msg,
687+ mpris::Service::Errors::DestroyingSession::name(),
688+ e.what());
689+ impl->access_bus()->send(reply);
690+ }
691+ }
692+
693 void handle_create_fixed_session(const core::dbus::Message::Ptr& msg)
694 {
695 try
696@@ -133,8 +333,8 @@
697 // Create new session
698 auto session_info = create_session_info();
699
700- dbus::types::ObjectPath op{session_info.first};
701- media::Player::PlayerKey key{session_info.second};
702+ dbus::types::ObjectPath op{std::get<0>(session_info)};
703+ media::Player::PlayerKey key{std::get<1>(session_info)};
704
705 media::Player::Configuration config
706 {
707@@ -149,7 +349,6 @@
708
709 configuration.player_store->add_player_for_key(key, session);
710
711-
712 named_player_map.insert(std::make_pair(name, key));
713
714 auto reply = dbus::Message::make_method_return(msg);
715@@ -233,6 +432,7 @@
716 impl->access_bus()->send(reply);
717 }
718
719+ media::apparmor::ubuntu::RequestContextResolver::Ptr request_context_resolver;
720 media::ServiceSkeleton* impl;
721 dbus::Object::Ptr object;
722
723@@ -240,6 +440,14 @@
724 ServiceSkeleton::Configuration configuration;
725 // We map named/fixed player instances to their respective keys.
726 std::map<std::string, media::Player::PlayerKey> named_player_map;
727+ // We map UUIDs to their respective keys.
728+ std::map<std::string, media::Player::PlayerKey> uuid_player_map;
729+ // We keep a list of keys and their respective owners and states.
730+ // value: (owner context, attached state, attached dbus name)
731+ std::map<media::Player::PlayerKey, std::tuple<std::string, bool, std::string>> player_owner_map;
732+
733+ boost::uuids::random_generator gen;
734+
735 // We expose the entire service as an MPRIS player.
736 struct Exported
737 {
738@@ -527,6 +735,21 @@
739 return d->configuration.impl->create_session(config);
740 }
741
742+void media::ServiceSkeleton::detach_session(const std::string& uuid, const media::Player::Configuration& config)
743+{
744+ return d->configuration.impl->detach_session(uuid, config);
745+}
746+
747+std::shared_ptr<media::Player> media::ServiceSkeleton::reattach_session(const std::string& uuid, const media::Player::Configuration& config)
748+{
749+ return d->configuration.impl->reattach_session(uuid, config);
750+}
751+
752+void media::ServiceSkeleton::destroy_session(const std::string& uuid, const media::Player::Configuration& config)
753+{
754+ return d->configuration.impl->destroy_session(uuid, config);
755+}
756+
757 std::shared_ptr<media::Player> media::ServiceSkeleton::create_fixed_session(const std::string& name, const media::Player::Configuration&config)
758 {
759 return d->configuration.impl->create_fixed_session(name, config);
760
761=== modified file 'src/core/media/service_skeleton.h'
762--- src/core/media/service_skeleton.h 2014-12-15 14:43:44 +0000
763+++ src/core/media/service_skeleton.h 2015-04-20 15:56:34 +0000
764@@ -19,6 +19,8 @@
765 #ifndef CORE_UBUNTU_MEDIA_SERVICE_SKELETON_H_
766 #define CORE_UBUNTU_MEDIA_SERVICE_SKELETON_H_
767
768+#include "apparmor/ubuntu.h"
769+
770 #include <core/media/service.h>
771
772 #include "cover_art_resolver.h"
773@@ -43,6 +45,7 @@
774 {
775 std::shared_ptr<Service> impl;
776 KeyedPlayerStore::Ptr player_store;
777+ helper::ExternalServices& external_services;
778 CoverArtResolver cover_art_resolver;
779 };
780
781@@ -51,6 +54,9 @@
782
783 // From media::Service
784 std::shared_ptr<Player> create_session(const Player::Configuration&);
785+ void detach_session(const std::string&, const Player::Configuration&);
786+ std::shared_ptr<Player> reattach_session(const std::string&, const Player::Configuration&);
787+ void destroy_session(const std::string&, const media::Player::Configuration&);
788 std::shared_ptr<Player> create_fixed_session(const std::string& name, const Player::Configuration&);
789 std::shared_ptr<Player> resume_session(Player::PlayerKey);
790 void pause_other_sessions(Player::PlayerKey key);
791
792=== modified file 'src/core/media/service_stub.cpp'
793--- src/core/media/service_stub.cpp 2015-04-20 15:56:34 +0000
794+++ src/core/media/service_stub.cpp 2015-04-20 15:56:34 +0000
795@@ -58,7 +58,7 @@
796 std::shared_ptr<media::Player> media::ServiceStub::create_session(const media::Player::Configuration&)
797 {
798 auto op = d->object->invoke_method_synchronously<mpris::Service::CreateSession,
799- dbus::types::ObjectPath>();
800+ std::tuple<dbus::types::ObjectPath, std::string>>();
801
802 if (op.is_error())
803 throw std::runtime_error("Problem creating session: " + op.error());
804@@ -67,8 +67,44 @@
805 {
806 shared_from_this(),
807 access_service(),
808- access_service()->object_for_path(op.value())
809- });
810+ access_service()->object_for_path(std::get<0>(op.value())),
811+ std::get<1>(op.value())
812+ });
813+}
814+
815+void media::ServiceStub::detach_session(const std::string& uuid, const media::Player::Configuration&)
816+{
817+ auto op = d->object->invoke_method_synchronously<mpris::Service::DetachSession,
818+ void>(uuid);
819+
820+ if (op.is_error())
821+ throw std::runtime_error("Problem detaching session: " + op.error());
822+}
823+
824+std::shared_ptr<media::Player> media::ServiceStub::reattach_session(const std::string& uuid, const media::Player::Configuration&)
825+{
826+ auto op = d->object->invoke_method_synchronously<mpris::Service::ReattachSession,
827+ dbus::types::ObjectPath>(uuid);
828+
829+ if (op.is_error())
830+ throw std::runtime_error("Problem reattaching session: " + op.error());
831+
832+ return std::shared_ptr<media::Player>(new media::PlayerStub
833+ {
834+ shared_from_this(),
835+ access_service(),
836+ access_service()->object_for_path(op.value()),
837+ uuid
838+ });
839+}
840+
841+void media::ServiceStub::destroy_session(const std::string& uuid, const media::Player::Configuration&)
842+{
843+ auto op = d->object->invoke_method_synchronously<mpris::Service::DestroySession,
844+ void>(uuid);
845+
846+ if (op.is_error())
847+ throw std::runtime_error("Problem destroying session: " + op.error());
848 }
849
850 std::shared_ptr<media::Player> media::ServiceStub::create_fixed_session(const std::string& name, const media::Player::Configuration&)
851
852=== modified file 'src/core/media/service_stub.h'
853--- src/core/media/service_stub.h 2014-10-23 14:42:59 +0000
854+++ src/core/media/service_stub.h 2015-04-20 15:56:34 +0000
855@@ -40,6 +40,9 @@
856 ~ServiceStub();
857
858 std::shared_ptr<Player> create_session(const Player::Configuration&);
859+ void detach_session(const std::string& uuid, const Player::Configuration&);
860+ std::shared_ptr<Player> reattach_session(const std::string& uuid, const Player::Configuration&);
861+ void destroy_session(const std::string& uuid, const Player::Configuration&);
862 std::shared_ptr<Player> create_fixed_session(const std::string& name, const Player::Configuration&);
863 std::shared_ptr<Player> resume_session(Player::PlayerKey key);
864 void pause_other_sessions(Player::PlayerKey key);
865
866=== modified file 'tests/test-track-list/test_track_list.cpp'
867--- tests/test-track-list/test_track_list.cpp 2015-04-20 15:56:34 +0000
868+++ tests/test-track-list/test_track_list.cpp 2015-04-20 15:56:34 +0000
869@@ -44,7 +44,7 @@
870 {
871 }
872
873-void media::TestTrackList::create_new_player_session()
874+std::string media::TestTrackList::create_new_player_session()
875 {
876 try {
877 m_hubPlayerSession = m_hubService->create_session(media::Player::Client::default_configuration());
878@@ -59,12 +59,53 @@
879 catch (std::runtime_error &e) {
880 cerr << "FATAL: Failed to retrieve the current player's TrackList: " << e.what() << endl;
881 }
882-}
883-
884-void media::TestTrackList::destroy_player_session()
885-{
886- // TODO: explicitly add a destroy session to the Service class after ricmm lands his new creation_session
887- // that returns a session ID. This will allow me to clear the tracklist after each test.
888+
889+ std::string uuid;
890+ try {
891+ uuid.assign(m_hubPlayerSession->uuid());
892+ }
893+ catch (std::runtime_error &e) {
894+ cerr << "FATAL: Failed to retrieve the current player's uuid: " << e.what() << endl;
895+ }
896+
897+ cout << "Connected to session " << uuid << endl;
898+ return uuid;
899+}
900+
901+void media::TestTrackList::detach_player_session(const std::string &uuid)
902+{
903+ try {
904+ m_hubService->detach_session(uuid, media::Player::Client::default_configuration());
905+ }
906+ catch (std::runtime_error &e) {
907+ cerr << "FATAL: Failed to detach the media-hub player session: " << e.what() << endl;
908+ }
909+
910+ cout << "Detached session " << uuid << endl;
911+}
912+
913+void media::TestTrackList::reattach_player_session(const std::string &uuid)
914+{
915+ try {
916+ m_hubPlayerSession = m_hubService->reattach_session(uuid, media::Player::Client::default_configuration());
917+ }
918+ catch (std::runtime_error &e) {
919+ cerr << "FATAL: Failed to reattach the media-hub player session: " << e.what() << endl;
920+ }
921+
922+ try {
923+ m_hubTrackList = m_hubPlayerSession->track_list();
924+ }
925+ catch (std::runtime_error &e) {
926+ cerr << "FATAL: Failed to retrieve the current player's TrackList: " << e.what() << endl;
927+ }
928+
929+ cout << "Re-connected to session " << uuid << endl;
930+}
931+
932+void media::TestTrackList::destroy_player_session(const std::string &uuid)
933+{
934+ m_hubService->destroy_session(uuid, media::Player::Client::default_configuration());
935 m_hubPlayerSession.reset();
936 }
937
938@@ -92,13 +133,13 @@
939 {
940 cout << "--> Running test: test_basic_playback" << std::endl;
941
942- core::Connection c =m_hubTrackList->on_track_added().connect([](const media::Track::Id &new_id)
943+ const std::string uuid = create_new_player_session();
944+
945+ core::Connection c = m_hubTrackList->on_track_added().connect([](const media::Track::Id &new_id)
946 {
947 cout << "Added track to TrackList with Id: " << new_id << endl;
948 });
949
950- //create_new_player_session();
951-
952 m_hubPlayerSession->open_uri(uri1);
953 if (!uri2.empty())
954 add_track(uri2);
955@@ -118,13 +159,34 @@
956
957 c.disconnect();
958
959- //destroy_player_session();
960+ destroy_player_session(uuid);
961+}
962+
963+void media::TestTrackList::test_tracklist_resume(const std::string &uri1, const std::string &uri2, const std::string &uuid)
964+{
965+ cout << "--> Running test: test_tracklist_resume" << std::endl;
966+
967+ add_track(uri1);
968+ add_track(uri2);
969+
970+ const size_t initial_size = m_hubTrackList->tracks().get().size();
971+ cout << "Tracklist size: " << initial_size << endl;
972+ detach_player_session(uuid);
973+ reattach_player_session(uuid);
974+ cout << "Tracklist size: " << m_hubTrackList->tracks().get().size() << endl;
975+
976+ m_hubPlayerSession->play();
977+
978+ if (initial_size != m_hubTrackList->tracks().get().size())
979+ cout << "Tracklist sizes are different, error in resuming" << endl;
980 }
981
982 void media::TestTrackList::test_ensure_tracklist_is_not_empty(const std::string &uri1, const std::string &uri2)
983 {
984 cout << "--> Running test: test_ensure_tracklist_is_not_empty" << std::endl;
985
986+ const std::string uuid = create_new_player_session();
987+
988 add_track(uri1);
989 if (!uri2.empty())
990 add_track(uri2);
991@@ -133,13 +195,15 @@
992 cout << "TrackList is not empty, test success" << endl;
993 else
994 cout << "TrackList is empty, test failure" << endl;
995+
996+ destroy_player_session(uuid);
997 }
998
999 void media::TestTrackList::test_has_next_track(const std::string &uri1, const std::string &uri2)
1000 {
1001 cout << "--> Running test: test_has_next_track" << std::endl;
1002
1003- //create_new_player_session();
1004+ const std::string uuid = create_new_player_session();
1005
1006 add_track(uri1);
1007 add_track(uri2);
1008@@ -158,13 +222,15 @@
1009 else
1010 cerr << "Playback did not start successfully" << endl;
1011
1012- //destroy_player_session();
1013+ destroy_player_session(uuid);
1014 }
1015
1016 void media::TestTrackList::test_shuffle(const std::string &uri1, const std::string &uri2, const std::string &uri3)
1017 {
1018 cout << "--> Running test: test_shuffle" << std::endl;
1019
1020+ const std::string uuid = create_new_player_session();
1021+
1022 add_track(uri1);
1023 add_track(uri2);
1024 add_track(uri3);
1025@@ -189,22 +255,27 @@
1026 cout << "Waiting for second track to finish playing..." << endl;
1027 wait_for_about_to_finish();
1028
1029- cout << "Going straight to the Track with Id of '/core/ubuntu/media/Service/sessions/0/TrackList/4'" << std::endl;
1030- const media::Track::Id id{"/core/ubuntu/media/Service/sessions/0/TrackList/4"};
1031+ const media::Track::Id id{m_hubTrackList->tracks().get()[3]};
1032+ cout << "Going straight to the Track with Id " << id << std::endl;
1033 const bool toggle_player_state = true;
1034 m_hubTrackList->go_to(id, toggle_player_state);
1035+
1036 cout << "Waiting for third track to finish playing..." << endl;
1037 wait_for_about_to_finish();
1038 }
1039 else
1040 cerr << "Playback did not start successfully" << endl;
1041+
1042+ destroy_player_session(uuid);
1043 }
1044
1045 void media::TestTrackList::test_remove_track(const std::string &uri1, const std::string &uri2, const std::string &uri3)
1046 {
1047 cout << "--> Running test: test_remove_track" << std::endl;
1048
1049- core::Connection c =m_hubTrackList->on_track_removed().connect([](const media::Track::Id &new_id)
1050+ const std::string uuid = create_new_player_session();
1051+
1052+ core::Connection c = m_hubTrackList->on_track_removed().connect([](const media::Track::Id &new_id)
1053 {
1054 cout << "Removed track from TrackList with Id: " << new_id << endl;
1055 });
1056@@ -220,7 +291,8 @@
1057 cout << "Waiting for first track to finish playing..." << endl;
1058 wait_for_about_to_finish();
1059
1060- const media::Track::Id id{"/core/ubuntu/media/Service/sessions/0/TrackList/1"};
1061+ const media::Track::Id id{m_hubTrackList->tracks().get()[1]};
1062+ cout << "Removing Track with Id of '" << id << "'" << std::endl;
1063 m_hubTrackList->remove_track(id);
1064
1065 cout << "Waiting for track after removed track to finish playing..." << endl;
1066@@ -228,6 +300,8 @@
1067 }
1068 else
1069 cerr << "Playback did not start successfully" << endl;
1070+
1071+ destroy_player_session(uuid);
1072 }
1073
1074 template<class T>
1075@@ -316,26 +390,31 @@
1076
1077 if (argc == 2)
1078 {
1079- tracklist->create_new_player_session();
1080 tracklist->test_basic_playback(argv[1]);
1081 tracklist->test_ensure_tracklist_is_not_empty(argv[1]);
1082 }
1083 else if (argc == 3)
1084 {
1085- tracklist->create_new_player_session();
1086 tracklist->test_basic_playback(argv[1], argv[2]);
1087 tracklist->test_ensure_tracklist_is_not_empty(argv[1], argv[2]);
1088 tracklist->test_has_next_track(argv[1], argv[2]);
1089 }
1090 else if (argc == 4)
1091 {
1092- tracklist->create_new_player_session();
1093 tracklist->test_basic_playback(argv[1]);
1094 tracklist->test_ensure_tracklist_is_not_empty(argv[1], argv[2]);
1095 tracklist->test_has_next_track(argv[1], argv[2]);
1096 tracklist->test_shuffle(argv[1], argv[2], argv[3]);
1097 tracklist->test_remove_track(argv[1], argv[2], argv[3]);
1098 }
1099+ else if (argc == 5)
1100+ {
1101+ std::string uuid = tracklist->create_new_player_session();
1102+
1103+ tracklist->test_tracklist_resume(argv[1], argv[2], uuid);
1104+
1105+ tracklist->destroy_player_session(uuid);
1106+ }
1107 else
1108 {
1109 cout << "Can't test TrackList, no track(s) specified." << endl;
1110
1111=== modified file 'tests/test-track-list/test_track_list.h'
1112--- tests/test-track-list/test_track_list.h 2015-04-20 15:56:34 +0000
1113+++ tests/test-track-list/test_track_list.h 2015-04-20 15:56:34 +0000
1114@@ -45,14 +45,19 @@
1115 TestTrackList();
1116 ~TestTrackList();
1117
1118- void create_new_player_session();
1119- void destroy_player_session();
1120+ std::string create_new_player_session();
1121+ void detach_player_session(const std::string &uuid);
1122+ void reattach_player_session(const std::string &uuid);
1123+ void destroy_player_session(const std::string &uuid);
1124
1125 void add_track(const std::string &uri, bool make_current = false);
1126
1127 // Takes in one or two files for playback, adds it/them to the TrackList, and plays
1128 void test_basic_playback(const std::string &uri1, const std::string &uri2 = std::string{});
1129
1130+ // Takes two uris and confirms that they remain after a detach/reattach
1131+ void test_tracklist_resume(const std::string &uri1, const std::string &uri2, const std::string &uuid);
1132+
1133 void test_ensure_tracklist_is_not_empty(const std::string &uri1, const std::string &uri2 = std::string{});
1134
1135 // Takes in one or two files for playback, adds it/them to the TrackList, plays and makes sure

Subscribers

People subscribed via source and target branches