Merge lp:~phablet-team/media-hub/bg-playlists-vivid into lp:media-hub/stable

Proposed by Jim Hodapp
Status: Merged
Approved by: Alfonso Sanchez-Beato
Approved revision: 168
Merged at revision: 151
Proposed branch: lp:~phablet-team/media-hub/bg-playlists-vivid
Merge into: lp:media-hub/stable
Diff against target: 1277 lines (+463/-218)
15 files modified
debian/changelog (+11/-5)
include/core/media/track.h (+1/-0)
include/core/media/track_list.h (+8/-1)
src/core/media/CMakeLists.txt (+1/-1)
src/core/media/gstreamer/engine.cpp (+7/-6)
src/core/media/mpris/track_list.h (+17/-6)
src/core/media/null_track_list.h (+0/-114)
src/core/media/player_implementation.cpp (+43/-17)
src/core/media/service_skeleton.cpp (+18/-15)
src/core/media/track.cpp (+7/-1)
src/core/media/track_list_implementation.cpp (+34/-2)
src/core/media/track_list_skeleton.cpp (+204/-32)
src/core/media/track_list_skeleton.h (+12/-3)
src/core/media/track_list_stub.cpp (+98/-15)
src/core/media/track_list_stub.h (+2/-0)
To merge this branch: bzr merge lp:~phablet-team/media-hub/bg-playlists-vivid
Reviewer Review Type Date Requested Status
Alfonso Sanchez-Beato Approve
Ubuntu Phablet Team Pending
Review via email: mp+266765@code.launchpad.net

Commit message

* Connected the TrackList signals on the stub side
* Make has_next() more reliable
* Make next() and previous() work better
* Fix various bugs that arose from testing the TrackList code

Description of the change

* Connected the TrackList signals on the stub side
* Make has_next() more reliable
* Make next() and previous() work better
* Fix various bugs that arose from testing the TrackList code

To post a comment you must log in.
165. By Jim Hodapp

Bump version to release on vivid+overlay

166. By Jim Hodapp

Bump version to release on vivid+overlay take 2

Revision history for this message
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote :

Overall looks good, although I have some comments.

review: Needs Fixing
167. By Jim Hodapp

Address code review comments.

168. By Jim Hodapp

Make sure media-hub debian/control version is UNRELEASED

Revision history for this message
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote :

LGTM

review: Approve
169. By Jim Hodapp

Don't export MPRIS MediaPlayer2 interface on dbus until we have a client that can take advantage of it

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/changelog'
2--- debian/changelog 2015-07-10 18:12:22 +0000
3+++ debian/changelog 2015-08-11 16:10:30 +0000
4@@ -1,4 +1,10 @@
5-media-hub (3.1.0+15.10.20150710-0ubuntu1) wily; urgency=medium
6+media-hub (3.1.0+15.04.20150710-0ubuntu2) UNRELEASED; urgency=medium
7+
8+ * Change version to vivid+overlay
9+
10+ -- Jim Hodapp <jim.hodapp@canonical.com> Fri, 07 Aug 2015 10:46:42 -0400
11+
12+media-hub (3.1.0+15.04.20150710-0ubuntu1) vivid; urgency=medium
13
14 [ CI Train Bot ]
15 * New rebuild forced.
16@@ -9,7 +15,7 @@
17
18 -- CI Train Bot <ci-train-bot@canonical.com> Fri, 10 Jul 2015 18:12:21 +0000
19
20-media-hub (3.1.0+15.10.20150604-0ubuntu1) wily; urgency=medium
21+media-hub (3.1.0+15.04.20150604-0ubuntu1) vivid; urgency=medium
22
23 [ CI Train Bot ]
24 * New rebuild forced.
25@@ -20,7 +26,7 @@
26
27 -- CI Train Bot <ci-train-bot@canonical.com> Thu, 04 Jun 2015 14:18:22 +0000
28
29-media-hub (3.1.0+15.10.20150601-0ubuntu1) wily; urgency=medium
30+media-hub (3.1.0+15.04.20150601-0ubuntu1) vivid; urgency=medium
31
32 [ CI Train Bot ]
33 * New rebuild forced.
34@@ -31,7 +37,7 @@
35
36 -- CI Train Bot <ci-train-bot@canonical.com> Mon, 01 Jun 2015 16:31:53 +0000
37
38-media-hub (3.1.0+15.10.20150527.1-0ubuntu1) wily; urgency=medium
39+media-hub (3.1.0+15.04.20150527.1-0ubuntu1) vivid; urgency=medium
40
41 [ CI Train Bot ]
42 * New rebuild forced.
43@@ -42,7 +48,7 @@
44
45 -- CI Train Bot <ci-train-bot@canonical.com> Wed, 27 May 2015 18:38:16 +0000
46
47-media-hub (3.1.0+15.10.20150522-0ubuntu1) wily; urgency=medium
48+media-hub (3.1.0+15.04.20150522-0ubuntu1) vivid; urgency=medium
49
50 [ Jim Hodapp ]
51 * Fix issues with not reporting failed decoding error to the client.
52
53=== modified file 'include/core/media/track.h'
54--- include/core/media/track.h 2014-02-12 16:02:48 +0000
55+++ include/core/media/track.h 2015-08-11 16:10:30 +0000
56@@ -107,6 +107,7 @@
57 bool operator==(const Track&) const;
58
59 virtual const Id& id() const;
60+ virtual const UriType& uri() const;
61 /*
62 class MetaData
63 {
64
65=== modified file 'include/core/media/track_list.h'
66--- include/core/media/track_list.h 2015-04-29 21:18:20 +0000
67+++ include/core/media/track_list.h 2015-08-11 16:10:30 +0000
68@@ -25,8 +25,9 @@
69
70 #include <functional>
71 #include <iosfwd>
72+#include <memory>
73+#include <string>
74 #include <vector>
75-#include <memory>
76
77 namespace core
78 {
79@@ -61,6 +62,9 @@
80 /** Gets all the metadata available for a given Track. */
81 virtual Track::MetaData query_meta_data_for_track(const Track::Id& id) = 0;
82
83+ /** Gets the URI for a given Track. */
84+ virtual Track::UriType query_uri_for_track(const Track::Id& id) = 0;
85+
86 /** Adds a URI in the TrackList. */
87 virtual void add_track_with_uri_at(const Track::UriType& uri, const Track::Id& position, bool make_current) = 0;
88
89@@ -108,6 +112,9 @@
90 /** Used to notify the Player of when the client requested that the Player should immediately play a new track. */
91 virtual const core::Signal<std::pair<Track::Id, bool>>& on_go_to_track() const = 0;
92
93+ /** Used to notify the Player of when the end of the tracklist has been reached. */
94+ virtual const core::Signal<void>& on_end_of_tracklist() const = 0;
95+
96 protected:
97 TrackList();
98 };
99
100=== modified file 'src/core/media/CMakeLists.txt'
101--- src/core/media/CMakeLists.txt 2015-02-24 15:22:19 +0000
102+++ src/core/media/CMakeLists.txt 2015-08-11 16:10:30 +0000
103@@ -88,7 +88,7 @@
104
105 client_death_observer.cpp
106 hashed_keyed_player_store.cpp
107- hybris_client_death_observer.cpp
108+ hybris_client_death_observer.cpp
109 cover_art_resolver.cpp
110 engine.cpp
111
112
113=== modified file 'src/core/media/gstreamer/engine.cpp'
114--- src/core/media/gstreamer/engine.cpp 2015-06-01 16:30:59 +0000
115+++ src/core/media/gstreamer/engine.cpp 2015-08-11 16:10:30 +0000
116@@ -374,7 +374,6 @@
117
118 gstreamer::Engine::Engine() : d(new Private{})
119 {
120- cout << "Creating a new Engine instance in " << __PRETTY_FUNCTION__ << endl;
121 d->state = media::Engine::State::no_media;
122 }
123
124@@ -413,7 +412,7 @@
125
126 bool gstreamer::Engine::play()
127 {
128- auto result = d->playbin.set_state_and_wait(GST_STATE_PLAYING);
129+ const auto result = d->playbin.set_state_and_wait(GST_STATE_PLAYING);
130
131 if (result)
132 {
133@@ -430,10 +429,12 @@
134 {
135 // No need to wait, and we can immediately return.
136 if (d->state == media::Engine::State::stopped)
137+ {
138+ std::cerr << "Current player state is already stopped - no need to change state to stopped" << std::endl;
139 return true;
140-
141- auto result = d->playbin.set_state_and_wait(GST_STATE_NULL);
142-
143+ }
144+
145+ const auto result = d->playbin.set_state_and_wait(GST_STATE_NULL);
146 if (result)
147 {
148 d->state = media::Engine::State::stopped;
149@@ -446,7 +447,7 @@
150
151 bool gstreamer::Engine::pause()
152 {
153- auto result = d->playbin.set_state_and_wait(GST_STATE_PAUSED);
154+ const auto result = d->playbin.set_state_and_wait(GST_STATE_PAUSED);
155
156 if (result)
157 {
158
159=== modified file 'src/core/media/mpris/track_list.h'
160--- src/core/media/mpris/track_list.h 2015-04-14 17:02:09 +0000
161+++ src/core/media/mpris/track_list.h 2015-08-11 16:10:30 +0000
162@@ -49,9 +49,11 @@
163 }
164
165 DBUS_CPP_METHOD_DEF(GetTracksMetadata, TrackList)
166+ DBUS_CPP_METHOD_DEF(GetTracksUri, TrackList)
167 DBUS_CPP_METHOD_DEF(AddTrack, TrackList)
168 DBUS_CPP_METHOD_DEF(RemoveTrack, TrackList)
169 DBUS_CPP_METHOD_DEF(GoTo, TrackList)
170+ DBUS_CPP_METHOD_DEF(Reset, TrackList)
171
172 struct Signals
173 {
174@@ -80,6 +82,13 @@
175
176 DBUS_CPP_SIGNAL_DEF
177 (
178+ TrackChanged,
179+ TrackList,
180+ core::ubuntu::media::Track::Id
181+ )
182+
183+ DBUS_CPP_SIGNAL_DEF
184+ (
185 TrackMetadataChanged,
186 TrackList,
187 BOOST_IDENTITY_TYPE((std::tuple<std::map<std::string, dbus::types::Variant>, dbus::types::ObjectPath>))
188@@ -118,15 +127,16 @@
189 : configuration(configuration),
190 properties
191 {
192- configuration.object->get_property<Properties::Tracks>(),
193- configuration.object->get_property<Properties::CanEditTracks>(),
194+ configuration.object->template get_property<Properties::Tracks>(),
195+ configuration.object->template get_property<Properties::CanEditTracks>(),
196 },
197 signals
198 {
199- configuration.object->get_signal<Signals::TrackListReplaced>(),
200- configuration.object->get_signal<Signals::TrackAdded>(),
201- configuration.object->get_signal<Signals::TrackRemoved>(),
202- configuration.object->get_signal<Signals::TrackMetadataChanged>(),
203+ configuration.object->template get_signal<Signals::TrackListReplaced>(),
204+ configuration.object->template get_signal<Signals::TrackAdded>(),
205+ configuration.object->template get_signal<Signals::TrackRemoved>(),
206+ configuration.object->template get_signal<Signals::TrackChanged>(),
207+ configuration.object->template get_signal<Signals::TrackMetadataChanged>(),
208 configuration.object->template get_signal<core::dbus::interfaces::Properties::Signals::PropertiesChanged>()
209 }
210 {
211@@ -169,6 +179,7 @@
212 core::dbus::Signal<Signals::TrackListReplaced, Signals::TrackListReplaced::ArgumentType>::Ptr tracklist_replaced;
213 core::dbus::Signal<Signals::TrackAdded, Signals::TrackAdded::ArgumentType>::Ptr track_added;
214 core::dbus::Signal<Signals::TrackRemoved, Signals::TrackRemoved::ArgumentType>::Ptr track_removed;
215+ core::dbus::Signal<Signals::TrackChanged, Signals::TrackChanged::ArgumentType>::Ptr track_changed;
216 core::dbus::Signal<Signals::TrackMetadataChanged, Signals::TrackMetadataChanged::ArgumentType>::Ptr track_metadata_changed;
217
218 dbus::Signal <core::dbus::interfaces::Properties::Signals::PropertiesChanged,
219
220=== removed file 'src/core/media/null_track_list.h'
221--- src/core/media/null_track_list.h 2014-12-15 21:02:14 +0000
222+++ src/core/media/null_track_list.h 1970-01-01 00:00:00 +0000
223@@ -1,114 +0,0 @@
224-/*
225- *
226- * This program is free software: you can redistribute it and/or modify it
227- * under the terms of the GNU Lesser General Public License version 3,
228- * as published by the Free Software Foundation.
229- *
230- * This program is distributed in the hope that it will be useful,
231- * but WITHOUT ANY WARRANTY; without even the implied warranty of
232- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
233- * GNU Lesser General Public License for more details.
234- *
235- * You should have received a copy of the GNU Lesser General Public License
236- * along with this program. If not, see <http://www.gnu.org/licenses/>.
237- *
238- * Authored by: Thomas Voß <thomas.voss@canonical.com>
239- */
240-
241-#ifndef CORE_MEDIA_NULL_TRACK_LIST_H_
242-#define CORE_MEDIA_NULL_TRACK_LIST_H_
243-
244-#include <core/media/track.h>
245-#include <core/media/track_list.h>
246-
247-namespace core
248-{
249-namespace ubuntu
250-{
251-namespace media
252-{
253-// A helper type to replace the playlist implementation below.
254-// Please note that this type is only a temporary manner. Ideally,
255-// the actual implementation should be injected as a dependency from the
256-// outside.
257-struct NullTrackList : public media::TrackList
258-{
259- NullTrackList() = default;
260-
261- bool has_next()
262- {
263- return false;
264- }
265-
266- media::Track::Id next()
267- {
268- return media::Track::Id{};
269- }
270-
271- media::Track::UriType query_uri_for_track(const media::Track::Id&)
272- {
273- return media::Track::UriType{};
274- }
275-
276- const core::Property<bool>& can_edit_tracks() const override
277- {
278- return props_and_sigs.can_edit_tracks;
279- }
280-
281- const core::Property<Container>& tracks() const override
282- {
283- return props_and_sigs.tracks;
284- }
285-
286- virtual media::Track::MetaData query_meta_data_for_track(const media::Track::Id&) override
287- {
288- return media::Track::MetaData{};
289- }
290-
291- void add_track_with_uri_at(const media::Track::UriType&, const media::Track::Id&, bool) override
292- {
293- }
294-
295- void remove_track(const media::Track::Id&) override
296- {
297- }
298-
299- void go_to(const media::Track::Id&) override
300- {
301- }
302-
303- const core::Signal<void>& on_track_list_replaced() const override
304- {
305- return props_and_sigs.on_track_list_replaced;
306- }
307-
308- const core::Signal<media::Track::Id>& on_track_added() const override
309- {
310- return props_and_sigs.on_track_added;
311- }
312-
313- const core::Signal<media::Track::Id>& on_track_removed() const override
314- {
315- return props_and_sigs.on_track_removed;
316- }
317-
318- const core::Signal<media::Track::Id>& on_track_changed() const override
319- {
320- return props_and_sigs.on_track_changed;
321- }
322-
323- struct
324- {
325- core::Property<bool> can_edit_tracks;
326- core::Property<TrackList::Container> tracks;
327- core::Signal<void> on_track_list_replaced;
328- core::Signal<media::Track::Id> on_track_added;
329- core::Signal<media::Track::Id> on_track_removed;
330- core::Signal<media::Track::Id> on_track_changed;
331- } props_and_sigs;
332-};
333-}
334-}
335-}
336-
337-#endif // CORE_MEDIA_NULL_TRACK_LIST_H_
338
339=== modified file 'src/core/media/player_implementation.cpp'
340--- src/core/media/player_implementation.cpp 2015-06-01 16:31:50 +0000
341+++ src/core/media/player_implementation.cpp 2015-08-11 16:10:30 +0000
342@@ -287,6 +287,20 @@
343 engine->reset();
344 }
345
346+ void open_first_track_from_tracklist(const media::Track::Id& id)
347+ {
348+ const Track::UriType uri = track_list->query_uri_for_track(id);
349+ if (!uri.empty())
350+ {
351+ // Using a TrackList for playback, added tracks via add_track(), but open_uri hasn't been called yet
352+ // to load a media resource
353+ std::cout << "Calling d->engine->open_resource_for_uri() for first track added only: " << uri << std::endl;
354+ std::cout << "\twith a Track::Id: " << id << std::endl;
355+ static const bool do_pipeline_reset = false;
356+ engine->open_resource_for_uri(uri, do_pipeline_reset);
357+ }
358+ }
359+
360 // Our link back to our parent.
361 media::PlayerImplementation<Parent>* parent;
362 // We just store the parameters passed on construction.
363@@ -375,6 +389,7 @@
364 // When the client changes the loop status, make sure to update the TrackList
365 Parent::loop_status().changed().connect([this](media::Player::LoopStatus loop_status)
366 {
367+ std::cout << "LoopStatus: " << loop_status << std::endl;
368 d->track_list->on_loop_status_changed(loop_status);
369 });
370
371@@ -408,18 +423,20 @@
372 if (d->doing_abandon)
373 return;
374
375+ // Prevent on_go_to_track from executing as it's not needed in this case. on_go_to_track
376+ // (see the lambda below) is only needed when the client explicitly calls next() not during
377+ // the about_to_finish condition
378+ d->doing_go_to_track.lock();
379+
380 Parent::about_to_finish()();
381
382- // This lambda needs to be mutually exclusive with the on_go_to_track lambda below
383- d->doing_go_to_track.lock();
384-
385 const media::Track::Id prev_track_id = d->track_list->current();
386 // Make sure that the TrackList keeps advancing. The logic for what gets played next,
387 // if anything at all, occurs in TrackListSkeleton::next()
388 const Track::UriType uri = d->track_list->query_uri_for_track(d->track_list->next());
389 if (prev_track_id != d->track_list->current() && !uri.empty())
390 {
391- std::cout << "Setting next track on playbin: " << uri << std::endl;
392+ std::cout << "Advancing to next track on playbin: " << uri << std::endl;
393 static const bool do_pipeline_reset = false;
394 d->engine->open_resource_for_uri(uri, do_pipeline_reset);
395 }
396@@ -457,12 +474,25 @@
397 Parent::error()(e);
398 });
399
400+ d->track_list->on_end_of_tracklist().connect([this]()
401+ {
402+ if (d->engine->state() != gstreamer::Engine::State::ready
403+ && d->engine->state() != gstreamer::Engine::State::stopped)
404+ {
405+ std::cout << "End of tracklist reached, stopping playback" << std::endl;
406+ d->engine->stop();
407+ }
408+ });
409+
410+
411 d->track_list->on_go_to_track().connect([this](std::pair<const media::Track::Id, bool> p)
412 {
413- // This prevents the TrackList from auto advancing in other areas such as the about_to_finish signal
414- // handler.
415 // This lambda needs to be mutually exclusive with the about_to_finish lambda above
416- d->doing_go_to_track.lock();
417+ const bool locked = d->doing_go_to_track.try_lock();
418+ // If the try_lock fails, it means that about_to_finish lambda above has it locked and it will
419+ // call d->engine->open_resource_for_uri()
420+ if (!locked)
421+ return;
422
423 const media::Track::Id id = p.first;
424 const bool toggle_player_state = p.second;
425@@ -483,7 +513,13 @@
426 d->engine->play();
427
428 d->doing_go_to_track.unlock();
429+ });
430
431+ d->track_list->on_track_added().connect([this](const media::Track::Id& id)
432+ {
433+ std::cout << "** Track was added, handling in PlayerImplementation" << std::endl;
434+ if (d->track_list->tracks()->size() == 1)
435+ d->open_first_track_from_tracklist(id);
436 });
437
438 // Everything is setup, we now subscribe to death notifications.
439@@ -614,16 +650,6 @@
440 template<typename Parent>
441 void media::PlayerImplementation<Parent>::play()
442 {
443- if (d->track_list != nullptr && d->track_list->tracks()->size() > 0 && d->engine->state() == media::Engine::State::no_media)
444- {
445- // Using a TrackList for playback, added tracks via add_track(), but open_uri hasn't been called yet
446- // to load a media resource
447- std::cout << "No media loaded yet, calling open_uri on first track in track_list" << std::endl;
448- static const bool do_pipeline_reset = true;
449- d->engine->open_resource_for_uri(d->track_list->query_uri_for_track(d->track_list->current()), do_pipeline_reset);
450- std::cout << *d->track_list << endl;
451- }
452-
453 d->engine->play();
454 }
455
456
457=== modified file 'src/core/media/service_skeleton.cpp'
458--- src/core/media/service_skeleton.cpp 2015-04-27 21:25:03 +0000
459+++ src/core/media/service_skeleton.cpp 2015-08-11 16:10:30 +0000
460@@ -139,7 +139,7 @@
461 fprintf(stderr, "%s():%d -- app_name='%s', attached\n", __func__, __LINE__, context.str().c_str());
462 player_owner_map.insert(std::make_pair(key, std::make_tuple(context.str(), true, msg->sender())));
463 });
464-
465+
466 auto reply = dbus::Message::make_method_return(msg);
467 reply->writer() << std::make_tuple(op, uuid);
468
469@@ -161,20 +161,24 @@
470 std::string uuid;
471 msg->reader() >> uuid;
472
473- auto key = uuid_player_map.at(uuid);
474+ // Make sure we don't try to do a lookup if the map is empty
475+ if (!uuid_player_map.empty())
476+ {
477+ const auto key = uuid_player_map.at(uuid);
478
479- if (player_owner_map.count(key) != 0) {
480- auto info = player_owner_map.at(key);
481- // Check if session is attached(1) and that the detachment
482- // request comes from the same peer(2) that created the session.
483- if (std::get<1>(info) && (std::get<2>(info) == msg->sender())) { // Player is attached
484- std::get<1>(info) = false; // Detached
485- std::get<2>(info).clear(); // Clear registered sender/peer
486- auto player = configuration.player_store->player_for_key(key);
487- player->lifetime().set(media::Player::Lifetime::resumable);
488+ if (player_owner_map.count(key) != 0) {
489+ auto info = player_owner_map.at(key);
490+ // Check if session is attached(1) and that the detachment
491+ // request comes from the same peer(2) that created the session.
492+ if (std::get<1>(info) && (std::get<2>(info) == msg->sender())) { // Player is attached
493+ std::get<1>(info) = false; // Detached
494+ std::get<2>(info).clear(); // Clear registered sender/peer
495+ auto player = configuration.player_store->player_for_key(key);
496+ player->lifetime().set(media::Player::Lifetime::resumable);
497+ }
498 }
499 }
500-
501+
502 auto reply = dbus::Message::make_method_return(msg);
503 impl->access_bus()->send(reply);
504
505@@ -256,7 +260,6 @@
506
507 void handle_destroy_session(const core::dbus::Message::Ptr& msg)
508 {
509-
510 try
511 {
512 std::string uuid;
513@@ -445,9 +448,9 @@
514 // We keep a list of keys and their respective owners and states.
515 // value: (owner context, attached state, attached dbus name)
516 std::map<media::Player::PlayerKey, std::tuple<std::string, bool, std::string>> player_owner_map;
517-
518+
519 boost::uuids::random_generator gen;
520-
521+
522 // We expose the entire service as an MPRIS player.
523 struct Exported
524 {
525
526=== modified file 'src/core/media/track.cpp'
527--- src/core/media/track.cpp 2014-02-12 15:53:57 +0000
528+++ src/core/media/track.cpp 2015-08-11 16:10:30 +0000
529@@ -25,9 +25,10 @@
530 struct media::Track::Private
531 {
532 media::Track::Id id;
533+ media::Track::UriType uri;
534 };
535
536-media::Track::Track(const media::Track::Id& id) : d(new Private{id})
537+media::Track::Track(const media::Track::Id& id) : d(new Private{id, std::string{}})
538 {
539 }
540
541@@ -39,3 +40,8 @@
542 {
543 return d->id;
544 }
545+
546+const media::Track::UriType& media::Track::uri() const
547+{
548+ return d->uri;
549+}
550
551=== modified file 'src/core/media/track_list_implementation.cpp'
552--- src/core/media/track_list_implementation.cpp 2015-05-22 21:19:28 +0000
553+++ src/core/media/track_list_implementation.cpp 2015-08-11 16:10:30 +0000
554@@ -59,7 +59,7 @@
555
556 media::Track::UriType media::TrackListImplementation::query_uri_for_track(const media::Track::Id& id)
557 {
558- auto it = d->meta_data_cache.find(id);
559+ const auto it = d->meta_data_cache.find(id);
560
561 if (it == d->meta_data_cache.end())
562 return Track::UriType{};
563@@ -69,7 +69,7 @@
564
565 media::Track::MetaData media::TrackListImplementation::query_meta_data_for_track(const media::Track::Id& id)
566 {
567- auto it = d->meta_data_cache.find(id);
568+ const auto it = d->meta_data_cache.find(id);
569
570 if (it == d->meta_data_cache.end())
571 return Track::MetaData{};
572@@ -87,10 +87,14 @@
573 std::stringstream ss; ss << d->object->path().as_string() << "/" << d->track_counter++;
574 Track::Id id{ss.str()};
575
576+ std::cout << "Adding Track::Id: " << id << std::endl;
577+ std::cout << "\tURI: " << uri << std::endl;
578+
579 auto result = tracks().update([this, id, position, make_current](TrackList::Container& container)
580 {
581 auto it = std::find(container.begin(), container.end(), position);
582 container.insert(it, id);
583+ std::cout << "container.size(): " << container.size() << std::endl;
584
585 return true;
586 });
587@@ -99,6 +103,8 @@
588 {
589 if (d->meta_data_cache.count(id) == 0)
590 {
591+ // FIXME: This code seems to conflict badly when called multiple times in a row: causes segfaults
592+#if 0
593 try {
594 d->meta_data_cache[id] = std::make_tuple(
595 uri,
596@@ -106,6 +112,11 @@
597 } catch (const std::runtime_error &e) {
598 std::cerr << "Failed to retrieve metadata for track '" << uri << "' (" << e.what() << ")" << std::endl;
599 }
600+#else
601+ d->meta_data_cache[id] = std::make_tuple(
602+ uri,
603+ core::ubuntu::media::Track::MetaData{});
604+#endif
605 } else
606 {
607 std::get<0>(d->meta_data_cache[id]) = uri;
608@@ -120,8 +131,14 @@
609 go_to(id, toggle_player_state);
610 }
611
612+ // Signal to the client that the current track has changed for the first track added to the TrackList
613+ if (tracks().get().size() == 1)
614+ on_track_changed()(id);
615+
616+ std::cout << "Signaling that we just added track id: " << id << std::endl;
617 // Signal to the client that a track was added to the TrackList
618 on_track_added()(id);
619+ std::cout << "Signaled that we just added track id: " << id << std::endl;
620 }
621 }
622
623@@ -133,6 +150,8 @@
624 return true;
625 });
626
627+ reset_current_iterator_if_needed();
628+
629 if (result)
630 {
631 d->meta_data_cache.erase(id);
632@@ -155,8 +174,12 @@
633 {
634 std::cout << __PRETTY_FUNCTION__ << std::endl;
635
636+ if (tracks().get().empty())
637+ return;
638+
639 auto result = tracks().update([this](TrackList::Container& container)
640 {
641+ // Save off the original TrackList ordering
642 d->original_tracklist.assign(container.begin(), container.end());
643 std::random_shuffle(container.begin(), container.end());
644 return true;
645@@ -173,8 +196,12 @@
646 {
647 std::cout << __PRETTY_FUNCTION__ << std::endl;
648
649+ if (tracks().get().empty() or d->original_tracklist.empty())
650+ return;
651+
652 auto result = tracks().update([this](TrackList::Container& container)
653 {
654+ // Restore the original TrackList ordering
655 container.assign(d->original_tracklist.begin(), d->original_tracklist.end());
656 return true;
657 });
658@@ -190,6 +217,9 @@
659 {
660 std::cout << __PRETTY_FUNCTION__ << std::endl;
661
662+ // Make sure playback stops
663+ on_end_of_tracklist()();
664+
665 auto result = tracks().update([this](TrackList::Container& container)
666 {
667 container.clear();
668@@ -198,5 +228,7 @@
669 return true;
670 });
671
672+ media::TrackListSkeleton::reset();
673+
674 (void) result;
675 }
676
677=== modified file 'src/core/media/track_list_skeleton.cpp'
678--- src/core/media/track_list_skeleton.cpp 2015-04-29 21:18:20 +0000
679+++ src/core/media/track_list_skeleton.cpp 2015-08-11 16:10:30 +0000
680@@ -60,6 +60,7 @@
681 {
682 skeleton.signals.track_added,
683 skeleton.signals.track_removed,
684+ skeleton.signals.track_changed,
685 skeleton.signals.tracklist_replaced
686 }
687 {
688@@ -70,15 +71,28 @@
689 media::Track::Id track;
690 msg->reader() >> track;
691
692- auto meta_data = impl->query_meta_data_for_track(track);
693+ const auto meta_data = impl->query_meta_data_for_track(track);
694
695- auto reply = dbus::Message::make_method_return(msg);
696+ const auto reply = dbus::Message::make_method_return(msg);
697 reply->writer() << *meta_data;
698 bus->send(reply);
699 }
700
701+ void handle_get_tracks_uri(const core::dbus::Message::Ptr& msg)
702+ {
703+ media::Track::Id track;
704+ msg->reader() >> track;
705+
706+ const auto uri = impl->query_uri_for_track(track);
707+
708+ const auto reply = dbus::Message::make_method_return(msg);
709+ reply->writer() << uri;
710+ bus->send(reply);
711+ }
712+
713 void handle_add_track_with_uri_at(const core::dbus::Message::Ptr& msg)
714 {
715+ std::cout << "*** " << __PRETTY_FUNCTION__ << std::endl;
716 request_context_resolver->resolve_context_for_dbus_name_async(msg->sender(), [this, msg](const media::apparmor::ubuntu::Context& context)
717 {
718 Track::UriType uri; media::Track::Id after; bool make_current;
719@@ -123,6 +137,14 @@
720 bus->send(reply);
721 }
722
723+ void handle_reset(const core::dbus::Message::Ptr& msg)
724+ {
725+ impl->reset();
726+
727+ auto reply = dbus::Message::make_method_return(msg);
728+ bus->send(reply);
729+ }
730+
731 media::TrackListSkeleton* impl;
732 dbus::Bus::Ptr bus;
733 dbus::Object::Ptr object;
734@@ -138,10 +160,12 @@
735 {
736 typedef core::dbus::Signal<mpris::TrackList::Signals::TrackAdded, mpris::TrackList::Signals::TrackAdded::ArgumentType> DBusTrackAddedSignal;
737 typedef core::dbus::Signal<mpris::TrackList::Signals::TrackRemoved, mpris::TrackList::Signals::TrackRemoved::ArgumentType> DBusTrackRemovedSignal;
738+ typedef core::dbus::Signal<mpris::TrackList::Signals::TrackChanged, mpris::TrackList::Signals::TrackChanged::ArgumentType> DBusTrackChangedSignal;
739 typedef core::dbus::Signal<mpris::TrackList::Signals::TrackListReplaced, mpris::TrackList::Signals::TrackListReplaced::ArgumentType> DBusTrackListReplacedSignal;
740
741 Signals(const std::shared_ptr<DBusTrackAddedSignal>& remote_track_added,
742 const std::shared_ptr<DBusTrackRemovedSignal>& remote_track_removed,
743+ const std::shared_ptr<DBusTrackChangedSignal>& remote_track_changed,
744 const std::shared_ptr<DBusTrackListReplacedSignal>& remote_track_list_replaced)
745 {
746 // Connect all of the MPRIS interface signals to be emitted over dbus
747@@ -155,6 +179,11 @@
748 remote_track_removed->emit(id);
749 });
750
751+ on_track_changed.connect([remote_track_changed](const media::Track::Id &id)
752+ {
753+ remote_track_changed->emit(id);
754+ });
755+
756 on_track_list_replaced.connect([remote_track_list_replaced](const media::TrackList::ContainerTrackIdTuple &tltuple)
757 {
758 remote_track_list_replaced->emit(tltuple);
759@@ -163,9 +192,10 @@
760
761 core::Signal<Track::Id> on_track_added;
762 core::Signal<Track::Id> on_track_removed;
763+ core::Signal<Track::Id> on_track_changed;
764 core::Signal<TrackList::ContainerTrackIdTuple> on_track_list_replaced;
765- core::Signal<Track::Id> on_track_changed;
766 core::Signal<std::pair<Track::Id, bool>> on_go_to_track;
767+ core::Signal<void> on_end_of_tracklist;
768 } signals;
769 };
770
771@@ -179,6 +209,11 @@
772 std::ref(d),
773 std::placeholders::_1));
774
775+ d->object->install_method_handler<mpris::TrackList::GetTracksUri>(
776+ std::bind(&Private::handle_get_tracks_uri,
777+ std::ref(d),
778+ std::placeholders::_1));
779+
780 d->object->install_method_handler<mpris::TrackList::AddTrack>(
781 std::bind(&Private::handle_add_track_with_uri_at,
782 std::ref(d),
783@@ -193,74 +228,184 @@
784 std::bind(&Private::handle_go_to,
785 std::ref(d),
786 std::placeholders::_1));
787+
788+ d->object->install_method_handler<mpris::TrackList::Reset>(
789+ std::bind(&Private::handle_reset,
790+ std::ref(d),
791+ std::placeholders::_1));
792 }
793
794 media::TrackListSkeleton::~TrackListSkeleton()
795 {
796 }
797
798-bool media::TrackListSkeleton::has_next() const
799+bool media::TrackListSkeleton::has_next()
800 {
801- const auto next_track = std::next(d->current_track);
802- std::cout << "has_next track? " << (next_track != tracks().get().end() ? "yes" : "no") << std::endl;
803- return next_track != tracks().get().end();
804+ if (tracks().get().empty())
805+ return false;
806+
807+ const auto next_track = std::next(current_iterator());
808+ return !is_last_track(next_track);
809 }
810
811-bool media::TrackListSkeleton::has_previous() const
812+bool media::TrackListSkeleton::has_previous()
813 {
814+ if (tracks().get().empty())
815+ return false;
816+
817 // If we are looping over the entire list, then there is always a previous track
818 if (d->loop_status == media::Player::LoopStatus::playlist)
819 return true;
820
821- std::cout << "has_previous track? " << (d->current_track != tracks().get().begin() ? "yes" : "no") << std::endl;
822- return d->current_track != tracks().get().begin();
823+ return d->current_track != std::begin(tracks().get());
824+}
825+
826+bool media::TrackListSkeleton::is_first_track(const ConstIterator &it)
827+{
828+ return it == std::begin(tracks().get());
829+}
830+
831+bool media::TrackListSkeleton::is_last_track(const TrackList::ConstIterator &it)
832+{
833+ return it == std::end(tracks().get());
834 }
835
836 media::Track::Id media::TrackListSkeleton::next()
837 {
838 std::cout << __PRETTY_FUNCTION__ << std::endl;
839 if (tracks().get().empty())
840- return *(d->current_track);
841+ return *(d->empty_iterator);
842+
843+ const auto next_track = std::next(current_iterator());
844+ bool do_go_to_next_track = false;
845+
846+ // End of the track reached so loop around to the beginning of the track
847+ if (d->loop_status == media::Player::LoopStatus::track)
848+ {
849+ std::cout << "Looping on the current track since LoopStatus is set to track" << std::endl;
850+ do_go_to_next_track = true;
851+ }
852+ // End of the tracklist reached so loop around to the beginning of the tracklist
853+ else if (d->loop_status == media::Player::LoopStatus::playlist && not has_next())
854+ {
855+ std::cout << "Looping on the tracklist since LoopStatus is set to playlist" << std::endl;
856+ d->current_track = tracks().get().begin();
857+ do_go_to_next_track = true;
858+ }
859+ else
860+ {
861+ // Next track is not the last track
862+ if (not is_last_track(next_track))
863+ {
864+ std::cout << "Advancing to next track: " << *(next_track) << std::endl;
865+ d->current_track = next_track;
866+ do_go_to_next_track = true;
867+ }
868+ // At the end of the tracklist and not set to loop, so we stop advancing the tracklist
869+ else
870+ {
871+ std::cout << "End of tracklist reached, not advancing to next since LoopStatus is set to none" << std::endl;
872+ on_end_of_tracklist()();
873+ }
874+ }
875+
876+ if (do_go_to_next_track)
877+ {
878+ on_track_changed()(*(current_iterator()));
879+ // Don't automatically call stop() and play() in player_implementation.cpp on_go_to_track()
880+ // since this breaks video playback when using open_uri() (stop() and play() are unwanted in
881+ // this scenario since the qtubuntu-media will handle this automatically)
882+ const bool toggle_player_state = false;
883+ const media::Track::Id id = *(current_iterator());
884+ const std::pair<const media::Track::Id, bool> p = std::make_pair(id, toggle_player_state);
885+ // Signal the PlayerImplementation to play the next track
886+ on_go_to_track()(p);
887+ }
888+
889+ return *(current_iterator());
890+}
891+
892+media::Track::Id media::TrackListSkeleton::previous()
893+{
894+ std::cout << __PRETTY_FUNCTION__ << std::endl;
895+ if (tracks().get().empty())
896+ return *(d->empty_iterator);
897+
898+ bool do_go_to_previous_track = false;
899
900 // Loop on the current track forever
901 if (d->loop_status == media::Player::LoopStatus::track)
902 {
903 std::cout << "Looping on the current track..." << std::endl;
904- return *(d->current_track);
905+ do_go_to_previous_track = true;
906 }
907 // Loop over the whole playlist and repeat
908- else if (d->loop_status == media::Player::LoopStatus::playlist && !has_next())
909+ else if (d->loop_status == media::Player::LoopStatus::playlist && is_first_track(current_iterator()))
910 {
911 std::cout << "Looping on the entire TrackList..." << std::endl;
912- d->current_track = tracks().get().begin();
913- return *(d->current_track);
914- }
915- else if (has_next())
916- {
917- // Keep returning the next track until the last track is reached
918- d->current_track = std::next(d->current_track);
919- std::cout << *this << std::endl;
920- }
921-
922- return *(d->current_track);
923-}
924-
925-media::Track::Id media::TrackListSkeleton::previous()
926-{
927- // TODO: Add logic to calculate the previous track
928- return *(d->current_track);
929+ d->current_track = std::prev(tracks().get().end());
930+ do_go_to_previous_track = true;
931+ }
932+ else
933+ {
934+ // Current track is not the first track
935+ if (not is_first_track(current_iterator()))
936+ {
937+ // Keep returning the previous track until the first track is reached
938+ d->current_track = std::prev(current_iterator());
939+ do_go_to_previous_track = true;
940+ }
941+ // At the beginning of the tracklist and not set to loop, so we stop advancing the tracklist
942+ else
943+ {
944+ std::cout << "Beginning of tracklist reached, not advancing to previous since LoopStatus is set to none" << std::endl;
945+ on_end_of_tracklist()();
946+ }
947+ }
948+
949+ if (do_go_to_previous_track)
950+ {
951+ on_track_changed()(*(current_iterator()));
952+ // Don't automatically call stop() and play() in player_implementation.cpp on_go_to_track()
953+ // since this breaks video playback when using open_uri() (stop() and play() are unwanted in
954+ // this scenario since the qtubuntu-media will handle this automatically)
955+ const bool toggle_player_state = false;
956+ const media::Track::Id id = *(current_iterator());
957+ const std::pair<const media::Track::Id, bool> p = std::make_pair(id, toggle_player_state);
958+ on_go_to_track()(p);
959+ }
960+
961+ return *(current_iterator());
962 }
963
964 const media::Track::Id& media::TrackListSkeleton::current()
965 {
966+ return *(current_iterator());
967+}
968+
969+const media::TrackList::ConstIterator& media::TrackListSkeleton::current_iterator()
970+{
971 // Prevent the TrackList from sitting at the end which will cause
972 // a segfault when calling current()
973 if (tracks().get().size() && (d->current_track == d->empty_iterator))
974+ {
975+ std::cout << "Wrapping d->current_track back to begin()" << std::endl;
976 d->current_track = d->skeleton.properties.tracks->get().begin();
977+ }
978 else if (tracks().get().empty())
979+ {
980 std::cerr << "TrackList is empty therefore there is no valid current track" << std::endl;
981-
982- return *(d->current_track);
983+ }
984+
985+ return d->current_track;
986+}
987+
988+void media::TrackListSkeleton::reset_current_iterator_if_needed()
989+{
990+ // If all tracks got removed then we need to keep a sane current
991+ // iterator for further use.
992+ if (tracks().get().empty())
993+ d->current_track = d->empty_iterator;
994 }
995
996 const core::Property<bool>& media::TrackListSkeleton::can_edit_tracks() const
997@@ -293,7 +438,18 @@
998 if (shuffle)
999 shuffle_tracks();
1000 else
1001+ {
1002+ // Save the current Track::Id of what's currently playing to restore after unshuffle
1003+ const media::Track::Id current_id = *(current_iterator());
1004+
1005 unshuffle_tracks();
1006+
1007+ // Since we use assign() in unshuffle_tracks, which invalidates existing iterators, we need
1008+ // to make sure that current is pointing to the right place
1009+ auto it = std::find(tracks().get().begin(), tracks().get().end(), current_id);
1010+ if (it != tracks().get().end())
1011+ d->current_track = it;
1012+ }
1013 }
1014
1015 const core::Property<media::TrackList::Container>& media::TrackListSkeleton::tracks() const
1016@@ -328,6 +484,11 @@
1017 return d->signals.on_go_to_track;
1018 }
1019
1020+const core::Signal<void>& media::TrackListSkeleton::on_end_of_tracklist() const
1021+{
1022+ return d->signals.on_end_of_tracklist;
1023+}
1024+
1025 core::Signal<media::TrackList::ContainerTrackIdTuple>& media::TrackListSkeleton::on_track_list_replaced()
1026 {
1027 return d->signals.on_track_list_replaced;
1028@@ -353,6 +514,17 @@
1029 return d->signals.on_go_to_track;
1030 }
1031
1032+core::Signal<void>& media::TrackListSkeleton::on_end_of_tracklist()
1033+{
1034+ return d->signals.on_end_of_tracklist;
1035+}
1036+
1037+void media::TrackListSkeleton::reset()
1038+{
1039+ std::cout << __PRETTY_FUNCTION__ << std::endl;
1040+ d->current_track = d->empty_iterator;
1041+}
1042+
1043 // operator<< pretty prints the given TrackList to the given output stream.
1044 inline std::ostream& media::operator<<(std::ostream& out, const media::TrackList& tracklist)
1045 {
1046
1047=== modified file 'src/core/media/track_list_skeleton.h'
1048--- src/core/media/track_list_skeleton.h 2015-04-29 21:18:20 +0000
1049+++ src/core/media/track_list_skeleton.h 2015-08-11 16:10:30 +0000
1050@@ -41,8 +41,8 @@
1051 const core::ubuntu::media::apparmor::ubuntu::RequestAuthenticator::Ptr& request_authenticator);
1052 ~TrackListSkeleton();
1053
1054- bool has_next() const;
1055- bool has_previous() const;
1056+ bool has_next();
1057+ bool has_previous();
1058 Track::Id next();
1059 Track::Id previous();
1060 const Track::Id& current();
1061@@ -52,10 +52,13 @@
1062
1063 const core::Signal<ContainerTrackIdTuple>& on_track_list_replaced() const;
1064 const core::Signal<Track::Id>& on_track_added() const;
1065+ core::Signal<Track::Id>& on_track_added();
1066 const core::Signal<Track::Id>& on_track_removed() const;
1067 const core::Signal<Track::Id>& on_track_changed() const;
1068 const core::Signal<std::pair<Track::Id, bool>>& on_go_to_track() const;
1069 core::Signal<std::pair<Track::Id, bool>>& on_go_to_track();
1070+ const core::Signal<void>& on_end_of_tracklist() const;
1071+ core::Signal<void>& on_end_of_tracklist();
1072 core::Signal<Track::Id>& on_track_removed();
1073
1074 core::Property<Container>& tracks();
1075@@ -67,12 +70,18 @@
1076 void on_shuffle_changed(bool shuffle);
1077
1078 protected:
1079+ inline bool is_first_track(const ConstIterator &it);
1080+ inline bool is_last_track(const ConstIterator &it);
1081+ inline const TrackList::ConstIterator& current_iterator();
1082+ void reset_current_iterator_if_needed();
1083+
1084 core::Property<bool>& can_edit_tracks();
1085
1086 core::Signal<ContainerTrackIdTuple>& on_track_list_replaced();
1087- core::Signal<Track::Id>& on_track_added();
1088 core::Signal<Track::Id>& on_track_changed();
1089
1090+ void reset();
1091+
1092 private:
1093 struct Private;
1094 std::unique_ptr<Private> d;
1095
1096=== modified file 'src/core/media/track_list_stub.cpp'
1097--- src/core/media/track_list_stub.cpp 2015-04-29 21:18:20 +0000
1098+++ src/core/media/track_list_stub.cpp 2015-08-11 16:10:30 +0000
1099@@ -48,7 +48,14 @@
1100 parent(parent),
1101 object(object),
1102 can_edit_tracks(object->get_property<mpris::TrackList::Properties::CanEditTracks>()),
1103- tracks(object->get_property<mpris::TrackList::Properties::Tracks>())
1104+ tracks(object->get_property<mpris::TrackList::Properties::Tracks>()),
1105+ signals
1106+ {
1107+ object->get_signal<mpris::TrackList::Signals::TrackAdded>(),
1108+ object->get_signal<mpris::TrackList::Signals::TrackRemoved>(),
1109+ object->get_signal<mpris::TrackList::Signals::TrackListReplaced>(),
1110+ object->get_signal<mpris::TrackList::Signals::TrackChanged>()
1111+ }
1112 {
1113 }
1114
1115@@ -59,11 +66,70 @@
1116 std::shared_ptr<core::dbus::Property<mpris::TrackList::Properties::CanEditTracks>> can_edit_tracks;
1117 std::shared_ptr<core::dbus::Property<mpris::TrackList::Properties::Tracks>> tracks;
1118
1119- core::Signal<media::TrackList::ContainerTrackIdTuple> on_track_list_replaced;
1120- core::Signal<Track::Id> on_track_added;
1121- core::Signal<Track::Id> on_track_removed;
1122- core::Signal<Track::Id> on_track_changed;
1123- core::Signal<std::pair<Track::Id, bool>> on_go_to_track;
1124+
1125+ struct Signals
1126+ {
1127+ typedef core::dbus::Signal<mpris::TrackList::Signals::TrackAdded, mpris::TrackList::Signals::TrackAdded::ArgumentType> DBusTrackAddedSignal;
1128+ typedef core::dbus::Signal<mpris::TrackList::Signals::TrackRemoved, mpris::TrackList::Signals::TrackRemoved::ArgumentType> DBusTrackRemovedSignal;
1129+ typedef core::dbus::Signal<mpris::TrackList::Signals::TrackListReplaced, mpris::TrackList::Signals::TrackListReplaced::ArgumentType> DBusTrackListReplacedSignal;
1130+ typedef core::dbus::Signal<mpris::TrackList::Signals::TrackChanged, mpris::TrackList::Signals::TrackChanged::ArgumentType> DBusTrackChangedSignal;
1131+
1132+ Signals(const std::shared_ptr<DBusTrackAddedSignal>& track_added,
1133+ const std::shared_ptr<DBusTrackRemovedSignal>& track_removed,
1134+ const std::shared_ptr<DBusTrackListReplacedSignal>& track_list_replaced,
1135+ const std::shared_ptr<DBusTrackChangedSignal>& track_changed)
1136+ : on_track_added(),
1137+ on_track_removed(),
1138+ on_track_list_replaced(),
1139+ on_track_changed(),
1140+ dbus
1141+ {
1142+ track_added,
1143+ track_removed,
1144+ track_list_replaced,
1145+ track_changed,
1146+ }
1147+ {
1148+ dbus.on_track_added->connect([this](const Track::Id& id)
1149+ {
1150+ std::cout << "OnTrackAdded signal arrived via the bus." << std::endl;
1151+ on_track_added(id);
1152+ });
1153+
1154+ dbus.on_track_removed->connect([this](const Track::Id& id)
1155+ {
1156+ std::cout << "OnTrackRemoved signal arrived via the bus." << std::endl;
1157+ on_track_removed(id);
1158+ });
1159+
1160+ dbus.on_track_list_replaced->connect([this](const media::TrackList::ContainerTrackIdTuple& list)
1161+ {
1162+ std::cout << "OnTrackListRemoved signal arrived via the bus." << std::endl;
1163+ on_track_list_replaced(list);
1164+ });
1165+
1166+ dbus.on_track_changed->connect([this](const Track::Id& id)
1167+ {
1168+ std::cout << "OnTrackChanged signal arrived via the bus." << std::endl;
1169+ on_track_changed(id);
1170+ });
1171+ }
1172+
1173+ core::Signal<Track::Id> on_track_added;
1174+ core::Signal<Track::Id> on_track_removed;
1175+ core::Signal<media::TrackList::ContainerTrackIdTuple> on_track_list_replaced;
1176+ core::Signal<Track::Id> on_track_changed;
1177+ core::Signal<std::pair<Track::Id, bool>> on_go_to_track;
1178+ core::Signal<void> on_end_of_tracklist;
1179+
1180+ struct DBus
1181+ {
1182+ std::shared_ptr<DBusTrackAddedSignal> on_track_added;
1183+ std::shared_ptr<DBusTrackRemovedSignal> on_track_removed;
1184+ std::shared_ptr<DBusTrackListReplacedSignal> on_track_list_replaced;
1185+ std::shared_ptr<DBusTrackChangedSignal> on_track_changed;
1186+ } dbus;
1187+ } signals;
1188 };
1189
1190 media::TrackListStub::TrackListStub(
1191@@ -104,6 +170,18 @@
1192 return md;
1193 }
1194
1195+media::Track::UriType media::TrackListStub::query_uri_for_track(const media::Track::Id& id)
1196+{
1197+ auto op = d->object->invoke_method_synchronously<
1198+ mpris::TrackList::GetTracksUri,
1199+ std::string>(id);
1200+
1201+ if (op.is_error())
1202+ throw std::runtime_error("Problem querying track for uri: " + op.error());
1203+
1204+ return op.value();
1205+}
1206+
1207 void media::TrackListStub::add_track_with_uri_at(
1208 const media::Track::UriType& uri,
1209 const media::Track::Id& id,
1210@@ -161,33 +239,38 @@
1211
1212 void media::TrackListStub::reset()
1213 {
1214- std::cerr << "reset() does nothing from the client side" << std::endl;
1215+ auto op = d->object->invoke_method_synchronously<mpris::TrackList::Reset, void>();
1216+
1217+ if (op.is_error())
1218+ throw std::runtime_error("Problem resetting tracklist: " + op.error());
1219 }
1220
1221 const core::Signal<media::TrackList::ContainerTrackIdTuple>& media::TrackListStub::on_track_list_replaced() const
1222 {
1223- std::cout << "Signal on_track_list_replaced arrived via the bus" << std::endl;
1224- return d->on_track_list_replaced;
1225+ return d->signals.on_track_list_replaced;
1226 }
1227
1228 const core::Signal<media::Track::Id>& media::TrackListStub::on_track_added() const
1229 {
1230- std::cout << "Signal on_track_added arrived via the bus" << std::endl;
1231- return d->on_track_added;
1232+ return d->signals.on_track_added;
1233 }
1234
1235 const core::Signal<media::Track::Id>& media::TrackListStub::on_track_removed() const
1236 {
1237- std::cout << "Signal on_track_removed arrived via the bus" << std::endl;
1238- return d->on_track_removed;
1239+ return d->signals.on_track_removed;
1240 }
1241
1242 const core::Signal<media::Track::Id>& media::TrackListStub::on_track_changed() const
1243 {
1244- return d->on_track_changed;
1245+ return d->signals.on_track_changed;
1246 }
1247
1248 const core::Signal<std::pair<media::Track::Id, bool>>& media::TrackListStub::on_go_to_track() const
1249 {
1250- return d->on_go_to_track;
1251+ return d->signals.on_go_to_track;
1252+}
1253+
1254+const core::Signal<void>& media::TrackListStub::on_end_of_tracklist() const
1255+{
1256+ return d->signals.on_end_of_tracklist;
1257 }
1258
1259=== modified file 'src/core/media/track_list_stub.h'
1260--- src/core/media/track_list_stub.h 2015-04-29 21:18:20 +0000
1261+++ src/core/media/track_list_stub.h 2015-08-11 16:10:30 +0000
1262@@ -45,6 +45,7 @@
1263 const core::Property<Container>& tracks() const;
1264
1265 Track::MetaData query_meta_data_for_track(const Track::Id& id);
1266+ Track::UriType query_uri_for_track(const Track::Id& id);
1267
1268 void add_track_with_uri_at(const Track::UriType& uri, const Track::Id& position, bool make_current);
1269 void remove_track(const Track::Id& id);
1270@@ -64,6 +65,7 @@
1271 const core::Signal<Track::Id>& on_track_removed() const;
1272 const core::Signal<Track::Id>& on_track_changed() const;
1273 const core::Signal<std::pair<Track::Id, bool>>& on_go_to_track() const;
1274+ const core::Signal<void>& on_end_of_tracklist() const;
1275
1276 private:
1277 struct Private;

Subscribers

People subscribed via source and target branches

to all changes: