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

Proposed by Jim Hodapp
Status: Superseded
Proposed branch: lp:~phablet-team/media-hub/bg-playlists-vivid
Merge into: lp:media-hub
Diff against target: 1364 lines (+469/-240)
19 files modified
CMakeLists.txt (+2/-2)
debian/changelog (+6/-0)
debian/control (+5/-9)
debian/libmedia-hub-common3.symbols (+0/-2)
debian/rules (+0/-8)
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 (+9/-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 (+19/-22)
src/core/media/track.cpp (+7/-1)
src/core/media/track_list_implementation.cpp (+36/-2)
src/core/media/track_list_skeleton.cpp (+203/-31)
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
Ubuntu Phablet Team Pending
Review via email: mp+266764@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

167. By Jim Hodapp

Address code review comments.

168. By Jim Hodapp

Make sure media-hub debian/control version is UNRELEASED

169. By Jim Hodapp

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

Unmerged revisions

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

Subscribers

People subscribed via source and target branches

to all changes: