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
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2015-04-10 16:21:16 +0000
+++ CMakeLists.txt 2015-08-03 18:09:14 +0000
@@ -2,8 +2,8 @@
22
3project(ubuntu-media-hub)3project(ubuntu-media-hub)
44
5set(UBUNTU_MEDIA_HUB_VERSION_MAJOR 3)5set(UBUNTU_MEDIA_HUB_VERSION_MAJOR 4)
6set(UBUNTU_MEDIA_HUB_VERSION_MINOR 1)6set(UBUNTU_MEDIA_HUB_VERSION_MINOR 0)
7set(UBUNTU_MEDIA_HUB_VERSION_PATCH 0)7set(UBUNTU_MEDIA_HUB_VERSION_PATCH 0)
88
9set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -fPIC -pthread")9set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -fPIC -pthread")
1010
=== modified file 'debian/changelog'
--- debian/changelog 2015-07-24 14:54:21 +0000
+++ debian/changelog 2015-08-03 18:09:14 +0000
@@ -1,3 +1,9 @@
1media-hub (4.0.0) wily; urgency=medium
2
3 * Bump major revision to account for toolchain update. Fixes LP:#1452331
4
5 -- Thomas Voß <thomas.voss@canonical.com> Thu, 23 Jul 2015 08:47:21 +0200
6
1media-hub (3.1.0+15.10.20150724-0ubuntu1) wily; urgency=medium7media-hub (3.1.0+15.10.20150724-0ubuntu1) wily; urgency=medium
28
3 [ Alfonso Sanchez-Beato (email Canonical) ]9 [ Alfonso Sanchez-Beato (email Canonical) ]
410
=== modified file 'debian/control'
--- debian/control 2015-03-12 11:38:32 +0000
+++ debian/control 2015-08-03 18:09:14 +0000
@@ -10,16 +10,12 @@
10 google-mock,10 google-mock,
11 graphviz,11 graphviz,
12 gstreamer1.0-plugins-good,12 gstreamer1.0-plugins-good,
13# We rely on C++11 features, and to prevent from ABI breaks
14# in libstdc++ causing us issues, we explicitly select a G++
15# version.
16 g++-4.9,
17 libboost-dev (>=1.53),13 libboost-dev (>=1.53),
18 libboost-filesystem-dev (>=1.53),14 libboost-filesystem-dev (>=1.53),
19 libboost-program-options-dev (>=1.53),15 libboost-program-options-dev (>=1.53),
20 libboost-system-dev (>=1.53),16 libboost-system-dev (>=1.53),
21 libdbus-1-dev,17 libdbus-1-dev,
22 libdbus-cpp-dev (>= 4.3.0),18 libdbus-cpp-dev (>= 5.0.0),
23 libgoogle-glog-dev,19 libgoogle-glog-dev,
24 libhybris-dev (>=0.1.0+git20131207+e452e83-0ubuntu30),20 libhybris-dev (>=0.1.0+git20131207+e452e83-0ubuntu30),
25 libprocess-cpp-dev,21 libprocess-cpp-dev,
@@ -39,8 +35,8 @@
39Section: libdevel35Section: libdevel
40Architecture: any36Architecture: any
41Multi-Arch: same37Multi-Arch: same
42Depends: libmedia-hub-common3 (= ${binary:Version}),38Depends: libmedia-hub-common4 (= ${binary:Version}),
43 libmedia-hub-client3 (= ${binary:Version}),39 libmedia-hub-client4 (= ${binary:Version}),
44 ${misc:Depends},40 ${misc:Depends},
45 libproperties-cpp-dev,41 libproperties-cpp-dev,
46Suggests: libmedia-hub-doc42Suggests: libmedia-hub-doc
@@ -61,7 +57,7 @@
61 .57 .
62 This package contains the runtime.58 This package contains the runtime.
6359
64Package: libmedia-hub-common360Package: libmedia-hub-common4
65Architecture: any61Architecture: any
66Multi-Arch: same62Multi-Arch: same
67Depends: ${misc:Depends},63Depends: ${misc:Depends},
@@ -72,7 +68,7 @@
72 .68 .
73 This package contains the common libraries.69 This package contains the common libraries.
7470
75Package: libmedia-hub-client371Package: libmedia-hub-client4
76Architecture: any72Architecture: any
77Multi-Arch: same73Multi-Arch: same
78Depends: ${misc:Depends},74Depends: ${misc:Depends},
7975
=== renamed file 'debian/libmedia-hub-client3.install' => 'debian/libmedia-hub-client4.install'
=== removed file 'debian/libmedia-hub-common3.symbols'
--- debian/libmedia-hub-common3.symbols 2014-11-26 12:45:39 +0000
+++ debian/libmedia-hub-common3.symbols 1970-01-01 00:00:00 +0000
@@ -1,2 +0,0 @@
1libmedia-hub-common.so.3 libmedia-hub-common3 #MINVER#
2 (c++)"core::ubuntu::media::the_session_bus()@Base" 2.0.0+14.10.20140910.2
30
=== renamed file 'debian/libmedia-hub-common3.install' => 'debian/libmedia-hub-common4.install'
=== modified file 'debian/rules'
--- debian/rules 2015-01-09 17:17:57 +0000
+++ debian/rules 2015-08-03 18:09:14 +0000
@@ -8,17 +8,9 @@
88
9include /usr/share/dpkg/default.mk9include /usr/share/dpkg/default.mk
1010
11# Explicitly selecting a G{CC,++}-version here to avoid accidental
12# ABI breaks introduced by toolchain updates.
13export CC=$(DEB_HOST_GNU_TYPE)-gcc-4.9
14export CXX=$(DEB_HOST_GNU_TYPE)-g++-4.9
15
16%:11%:
17 dh $@ --fail-missing --parallel -- -B build 12 dh $@ --fail-missing --parallel -- -B build
1813
19override_dh_auto_configure:
20 dh_auto_configure -- -DCMAKE_C_COMPILER=$(CC) -DCMAKE_CXX_COMPILER=$(CXX)
21
22override_dh_auto_test:14override_dh_auto_test:
23 env -u LD_PRELOAD dh_auto_test15 env -u LD_PRELOAD dh_auto_test
2416
2517
=== modified file 'include/core/media/track.h'
--- include/core/media/track.h 2014-02-12 16:02:48 +0000
+++ include/core/media/track.h 2015-08-03 18:09:14 +0000
@@ -107,6 +107,7 @@
107 bool operator==(const Track&) const;107 bool operator==(const Track&) const;
108108
109 virtual const Id& id() const;109 virtual const Id& id() const;
110 virtual const UriType& uri() const;
110 /*111 /*
111 class MetaData112 class MetaData
112 {113 {
113114
=== modified file 'include/core/media/track_list.h'
--- include/core/media/track_list.h 2015-04-29 21:18:20 +0000
+++ include/core/media/track_list.h 2015-08-03 18:09:14 +0000
@@ -25,8 +25,9 @@
2525
26#include <functional>26#include <functional>
27#include <iosfwd>27#include <iosfwd>
28#include <memory>
29#include <string>
28#include <vector>30#include <vector>
29#include <memory>
3031
31namespace core32namespace core
32{33{
@@ -61,6 +62,9 @@
61 /** Gets all the metadata available for a given Track. */62 /** Gets all the metadata available for a given Track. */
62 virtual Track::MetaData query_meta_data_for_track(const Track::Id& id) = 0;63 virtual Track::MetaData query_meta_data_for_track(const Track::Id& id) = 0;
6364
65 /** Gets the URI for a given Track. */
66 virtual Track::UriType query_uri_for_track(const Track::Id& id) = 0;
67
64 /** Adds a URI in the TrackList. */68 /** Adds a URI in the TrackList. */
65 virtual void add_track_with_uri_at(const Track::UriType& uri, const Track::Id& position, bool make_current) = 0;69 virtual void add_track_with_uri_at(const Track::UriType& uri, const Track::Id& position, bool make_current) = 0;
6670
@@ -108,6 +112,9 @@
108 /** Used to notify the Player of when the client requested that the Player should immediately play a new track. */112 /** Used to notify the Player of when the client requested that the Player should immediately play a new track. */
109 virtual const core::Signal<std::pair<Track::Id, bool>>& on_go_to_track() const = 0;113 virtual const core::Signal<std::pair<Track::Id, bool>>& on_go_to_track() const = 0;
110114
115 /** Used to notify the Player of when the end of the tracklist has been reached. */
116 virtual const core::Signal<void>& on_end_of_tracklist() const = 0;
117
111protected:118protected:
112 TrackList();119 TrackList();
113};120};
114121
=== modified file 'src/core/media/CMakeLists.txt'
--- src/core/media/CMakeLists.txt 2015-02-24 15:22:19 +0000
+++ src/core/media/CMakeLists.txt 2015-08-03 18:09:14 +0000
@@ -88,7 +88,7 @@
8888
89 client_death_observer.cpp89 client_death_observer.cpp
90 hashed_keyed_player_store.cpp90 hashed_keyed_player_store.cpp
91 hybris_client_death_observer.cpp 91 hybris_client_death_observer.cpp
92 cover_art_resolver.cpp92 cover_art_resolver.cpp
93 engine.cpp93 engine.cpp
9494
9595
=== modified file 'src/core/media/gstreamer/engine.cpp'
--- src/core/media/gstreamer/engine.cpp 2015-06-01 16:30:59 +0000
+++ src/core/media/gstreamer/engine.cpp 2015-08-03 18:09:14 +0000
@@ -374,7 +374,6 @@
374374
375gstreamer::Engine::Engine() : d(new Private{})375gstreamer::Engine::Engine() : d(new Private{})
376{376{
377 cout << "Creating a new Engine instance in " << __PRETTY_FUNCTION__ << endl;
378 d->state = media::Engine::State::no_media;377 d->state = media::Engine::State::no_media;
379}378}
380379
@@ -413,7 +412,7 @@
413412
414bool gstreamer::Engine::play()413bool gstreamer::Engine::play()
415{414{
416 auto result = d->playbin.set_state_and_wait(GST_STATE_PLAYING);415 const auto result = d->playbin.set_state_and_wait(GST_STATE_PLAYING);
417416
418 if (result)417 if (result)
419 {418 {
@@ -430,10 +429,14 @@
430{429{
431 // No need to wait, and we can immediately return.430 // No need to wait, and we can immediately return.
432 if (d->state == media::Engine::State::stopped)431 if (d->state == media::Engine::State::stopped)
432 //if (d->state != media::Engine::State::playing ||
433 // d->state == media::Engine::State::paused)
434 {
435 std::cout << "Current player state is already stopped - no need to change state to stopped" << std::endl;
433 return true;436 return true;
434437 }
435 auto result = d->playbin.set_state_and_wait(GST_STATE_NULL);438
436439 const auto result = d->playbin.set_state_and_wait(GST_STATE_NULL);
437 if (result)440 if (result)
438 {441 {
439 d->state = media::Engine::State::stopped;442 d->state = media::Engine::State::stopped;
@@ -446,7 +449,7 @@
446449
447bool gstreamer::Engine::pause()450bool gstreamer::Engine::pause()
448{451{
449 auto result = d->playbin.set_state_and_wait(GST_STATE_PAUSED);452 const auto result = d->playbin.set_state_and_wait(GST_STATE_PAUSED);
450453
451 if (result)454 if (result)
452 {455 {
453456
=== modified file 'src/core/media/mpris/track_list.h'
--- src/core/media/mpris/track_list.h 2015-04-14 17:02:09 +0000
+++ src/core/media/mpris/track_list.h 2015-08-03 18:09:14 +0000
@@ -49,9 +49,11 @@
49 }49 }
5050
51 DBUS_CPP_METHOD_DEF(GetTracksMetadata, TrackList)51 DBUS_CPP_METHOD_DEF(GetTracksMetadata, TrackList)
52 DBUS_CPP_METHOD_DEF(GetTracksUri, TrackList)
52 DBUS_CPP_METHOD_DEF(AddTrack, TrackList)53 DBUS_CPP_METHOD_DEF(AddTrack, TrackList)
53 DBUS_CPP_METHOD_DEF(RemoveTrack, TrackList)54 DBUS_CPP_METHOD_DEF(RemoveTrack, TrackList)
54 DBUS_CPP_METHOD_DEF(GoTo, TrackList)55 DBUS_CPP_METHOD_DEF(GoTo, TrackList)
56 DBUS_CPP_METHOD_DEF(Reset, TrackList)
5557
56 struct Signals58 struct Signals
57 {59 {
@@ -80,6 +82,13 @@
8082
81 DBUS_CPP_SIGNAL_DEF83 DBUS_CPP_SIGNAL_DEF
82 (84 (
85 TrackChanged,
86 TrackList,
87 core::ubuntu::media::Track::Id
88 )
89
90 DBUS_CPP_SIGNAL_DEF
91 (
83 TrackMetadataChanged,92 TrackMetadataChanged,
84 TrackList,93 TrackList,
85 BOOST_IDENTITY_TYPE((std::tuple<std::map<std::string, dbus::types::Variant>, dbus::types::ObjectPath>))94 BOOST_IDENTITY_TYPE((std::tuple<std::map<std::string, dbus::types::Variant>, dbus::types::ObjectPath>))
@@ -118,15 +127,16 @@
118 : configuration(configuration),127 : configuration(configuration),
119 properties128 properties
120 {129 {
121 configuration.object->get_property<Properties::Tracks>(),130 configuration.object->template get_property<Properties::Tracks>(),
122 configuration.object->get_property<Properties::CanEditTracks>(),131 configuration.object->template get_property<Properties::CanEditTracks>(),
123 },132 },
124 signals133 signals
125 {134 {
126 configuration.object->get_signal<Signals::TrackListReplaced>(),135 configuration.object->template get_signal<Signals::TrackListReplaced>(),
127 configuration.object->get_signal<Signals::TrackAdded>(),136 configuration.object->template get_signal<Signals::TrackAdded>(),
128 configuration.object->get_signal<Signals::TrackRemoved>(),137 configuration.object->template get_signal<Signals::TrackRemoved>(),
129 configuration.object->get_signal<Signals::TrackMetadataChanged>(),138 configuration.object->template get_signal<Signals::TrackChanged>(),
139 configuration.object->template get_signal<Signals::TrackMetadataChanged>(),
130 configuration.object->template get_signal<core::dbus::interfaces::Properties::Signals::PropertiesChanged>()140 configuration.object->template get_signal<core::dbus::interfaces::Properties::Signals::PropertiesChanged>()
131 }141 }
132 {142 {
@@ -169,6 +179,7 @@
169 core::dbus::Signal<Signals::TrackListReplaced, Signals::TrackListReplaced::ArgumentType>::Ptr tracklist_replaced;179 core::dbus::Signal<Signals::TrackListReplaced, Signals::TrackListReplaced::ArgumentType>::Ptr tracklist_replaced;
170 core::dbus::Signal<Signals::TrackAdded, Signals::TrackAdded::ArgumentType>::Ptr track_added;180 core::dbus::Signal<Signals::TrackAdded, Signals::TrackAdded::ArgumentType>::Ptr track_added;
171 core::dbus::Signal<Signals::TrackRemoved, Signals::TrackRemoved::ArgumentType>::Ptr track_removed;181 core::dbus::Signal<Signals::TrackRemoved, Signals::TrackRemoved::ArgumentType>::Ptr track_removed;
182 core::dbus::Signal<Signals::TrackChanged, Signals::TrackChanged::ArgumentType>::Ptr track_changed;
172 core::dbus::Signal<Signals::TrackMetadataChanged, Signals::TrackMetadataChanged::ArgumentType>::Ptr track_metadata_changed;183 core::dbus::Signal<Signals::TrackMetadataChanged, Signals::TrackMetadataChanged::ArgumentType>::Ptr track_metadata_changed;
173184
174 dbus::Signal <core::dbus::interfaces::Properties::Signals::PropertiesChanged,185 dbus::Signal <core::dbus::interfaces::Properties::Signals::PropertiesChanged,
175186
=== removed file 'src/core/media/null_track_list.h'
--- src/core/media/null_track_list.h 2014-12-15 21:02:14 +0000
+++ src/core/media/null_track_list.h 1970-01-01 00:00:00 +0000
@@ -1,114 +0,0 @@
1/*
2 *
3 * This program is free software: you can redistribute it and/or modify it
4 * under the terms of the GNU Lesser General Public License version 3,
5 * as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *
15 * Authored by: Thomas Voß <thomas.voss@canonical.com>
16 */
17
18#ifndef CORE_MEDIA_NULL_TRACK_LIST_H_
19#define CORE_MEDIA_NULL_TRACK_LIST_H_
20
21#include <core/media/track.h>
22#include <core/media/track_list.h>
23
24namespace core
25{
26namespace ubuntu
27{
28namespace media
29{
30// A helper type to replace the playlist implementation below.
31// Please note that this type is only a temporary manner. Ideally,
32// the actual implementation should be injected as a dependency from the
33// outside.
34struct NullTrackList : public media::TrackList
35{
36 NullTrackList() = default;
37
38 bool has_next()
39 {
40 return false;
41 }
42
43 media::Track::Id next()
44 {
45 return media::Track::Id{};
46 }
47
48 media::Track::UriType query_uri_for_track(const media::Track::Id&)
49 {
50 return media::Track::UriType{};
51 }
52
53 const core::Property<bool>& can_edit_tracks() const override
54 {
55 return props_and_sigs.can_edit_tracks;
56 }
57
58 const core::Property<Container>& tracks() const override
59 {
60 return props_and_sigs.tracks;
61 }
62
63 virtual media::Track::MetaData query_meta_data_for_track(const media::Track::Id&) override
64 {
65 return media::Track::MetaData{};
66 }
67
68 void add_track_with_uri_at(const media::Track::UriType&, const media::Track::Id&, bool) override
69 {
70 }
71
72 void remove_track(const media::Track::Id&) override
73 {
74 }
75
76 void go_to(const media::Track::Id&) override
77 {
78 }
79
80 const core::Signal<void>& on_track_list_replaced() const override
81 {
82 return props_and_sigs.on_track_list_replaced;
83 }
84
85 const core::Signal<media::Track::Id>& on_track_added() const override
86 {
87 return props_and_sigs.on_track_added;
88 }
89
90 const core::Signal<media::Track::Id>& on_track_removed() const override
91 {
92 return props_and_sigs.on_track_removed;
93 }
94
95 const core::Signal<media::Track::Id>& on_track_changed() const override
96 {
97 return props_and_sigs.on_track_changed;
98 }
99
100 struct
101 {
102 core::Property<bool> can_edit_tracks;
103 core::Property<TrackList::Container> tracks;
104 core::Signal<void> on_track_list_replaced;
105 core::Signal<media::Track::Id> on_track_added;
106 core::Signal<media::Track::Id> on_track_removed;
107 core::Signal<media::Track::Id> on_track_changed;
108 } props_and_sigs;
109};
110}
111}
112}
113
114#endif // CORE_MEDIA_NULL_TRACK_LIST_H_
1150
=== modified file 'src/core/media/player_implementation.cpp'
--- src/core/media/player_implementation.cpp 2015-06-01 16:31:50 +0000
+++ src/core/media/player_implementation.cpp 2015-08-03 18:09:14 +0000
@@ -287,6 +287,20 @@
287 engine->reset();287 engine->reset();
288 }288 }
289289
290 void open_first_track_from_tracklist(const media::Track::Id& id)
291 {
292 const Track::UriType uri = track_list->query_uri_for_track(id);
293 if (!uri.empty())
294 {
295 // Using a TrackList for playback, added tracks via add_track(), but open_uri hasn't been called yet
296 // to load a media resource
297 std::cout << "Calling d->engine->open_resource_for_uri() for first track added only: " << uri << std::endl;
298 std::cout << "\twith a Track::Id: " << id << std::endl;
299 static const bool do_pipeline_reset = false;
300 engine->open_resource_for_uri(uri, do_pipeline_reset);
301 }
302 }
303
290 // Our link back to our parent.304 // Our link back to our parent.
291 media::PlayerImplementation<Parent>* parent;305 media::PlayerImplementation<Parent>* parent;
292 // We just store the parameters passed on construction.306 // We just store the parameters passed on construction.
@@ -375,6 +389,7 @@
375 // When the client changes the loop status, make sure to update the TrackList389 // When the client changes the loop status, make sure to update the TrackList
376 Parent::loop_status().changed().connect([this](media::Player::LoopStatus loop_status)390 Parent::loop_status().changed().connect([this](media::Player::LoopStatus loop_status)
377 {391 {
392 std::cout << "LoopStatus: " << loop_status << std::endl;
378 d->track_list->on_loop_status_changed(loop_status);393 d->track_list->on_loop_status_changed(loop_status);
379 });394 });
380395
@@ -408,18 +423,20 @@
408 if (d->doing_abandon)423 if (d->doing_abandon)
409 return;424 return;
410425
426 // Prevent on_go_to_track from executing as it's not needed in this case. on_go_to_track
427 // (see the lambda below) is only needed when the client explicitly calls next() not during
428 // the about_to_finish condition
429 d->doing_go_to_track.lock();
430
411 Parent::about_to_finish()();431 Parent::about_to_finish()();
412432
413 // This lambda needs to be mutually exclusive with the on_go_to_track lambda below
414 d->doing_go_to_track.lock();
415
416 const media::Track::Id prev_track_id = d->track_list->current();433 const media::Track::Id prev_track_id = d->track_list->current();
417 // Make sure that the TrackList keeps advancing. The logic for what gets played next,434 // Make sure that the TrackList keeps advancing. The logic for what gets played next,
418 // if anything at all, occurs in TrackListSkeleton::next()435 // if anything at all, occurs in TrackListSkeleton::next()
419 const Track::UriType uri = d->track_list->query_uri_for_track(d->track_list->next());436 const Track::UriType uri = d->track_list->query_uri_for_track(d->track_list->next());
420 if (prev_track_id != d->track_list->current() && !uri.empty())437 if (prev_track_id != d->track_list->current() && !uri.empty())
421 {438 {
422 std::cout << "Setting next track on playbin: " << uri << std::endl;439 std::cout << "Advancing to next track on playbin: " << uri << std::endl;
423 static const bool do_pipeline_reset = false;440 static const bool do_pipeline_reset = false;
424 d->engine->open_resource_for_uri(uri, do_pipeline_reset);441 d->engine->open_resource_for_uri(uri, do_pipeline_reset);
425 }442 }
@@ -457,12 +474,25 @@
457 Parent::error()(e);474 Parent::error()(e);
458 });475 });
459476
477 d->track_list->on_end_of_tracklist().connect([this]()
478 {
479 if (d->engine->state() != gstreamer::Engine::State::ready
480 && d->engine->state() != gstreamer::Engine::State::stopped)
481 {
482 std::cout << "End of tracklist reached, stopping playback" << std::endl;
483 d->engine->stop();
484 }
485 });
486
487
460 d->track_list->on_go_to_track().connect([this](std::pair<const media::Track::Id, bool> p)488 d->track_list->on_go_to_track().connect([this](std::pair<const media::Track::Id, bool> p)
461 {489 {
462 // This prevents the TrackList from auto advancing in other areas such as the about_to_finish signal
463 // handler.
464 // This lambda needs to be mutually exclusive with the about_to_finish lambda above490 // This lambda needs to be mutually exclusive with the about_to_finish lambda above
465 d->doing_go_to_track.lock();491 const bool locked = d->doing_go_to_track.try_lock();
492 // If the try_lock fails, it means that about_to_finish lambda above has it locked and it will
493 // call d->engine->open_resource_for_uri()
494 if (!locked)
495 return;
466496
467 const media::Track::Id id = p.first;497 const media::Track::Id id = p.first;
468 const bool toggle_player_state = p.second;498 const bool toggle_player_state = p.second;
@@ -483,7 +513,13 @@
483 d->engine->play();513 d->engine->play();
484514
485 d->doing_go_to_track.unlock();515 d->doing_go_to_track.unlock();
516 });
486517
518 d->track_list->on_track_added().connect([this](const media::Track::Id& id)
519 {
520 std::cout << "** Track was added, handling in PlayerImplementation" << std::endl;
521 if (d->track_list->tracks()->size() == 1)
522 d->open_first_track_from_tracklist(id);
487 });523 });
488524
489 // Everything is setup, we now subscribe to death notifications.525 // Everything is setup, we now subscribe to death notifications.
@@ -614,16 +650,6 @@
614template<typename Parent>650template<typename Parent>
615void media::PlayerImplementation<Parent>::play()651void media::PlayerImplementation<Parent>::play()
616{652{
617 if (d->track_list != nullptr && d->track_list->tracks()->size() > 0 && d->engine->state() == media::Engine::State::no_media)
618 {
619 // Using a TrackList for playback, added tracks via add_track(), but open_uri hasn't been called yet
620 // to load a media resource
621 std::cout << "No media loaded yet, calling open_uri on first track in track_list" << std::endl;
622 static const bool do_pipeline_reset = true;
623 d->engine->open_resource_for_uri(d->track_list->query_uri_for_track(d->track_list->current()), do_pipeline_reset);
624 std::cout << *d->track_list << endl;
625 }
626
627 d->engine->play();653 d->engine->play();
628}654}
629655
630656
=== modified file 'src/core/media/service_skeleton.cpp'
--- src/core/media/service_skeleton.cpp 2015-04-27 21:25:03 +0000
+++ src/core/media/service_skeleton.cpp 2015-08-03 18:09:14 +0000
@@ -139,7 +139,7 @@
139 fprintf(stderr, "%s():%d -- app_name='%s', attached\n", __func__, __LINE__, context.str().c_str());139 fprintf(stderr, "%s():%d -- app_name='%s', attached\n", __func__, __LINE__, context.str().c_str());
140 player_owner_map.insert(std::make_pair(key, std::make_tuple(context.str(), true, msg->sender())));140 player_owner_map.insert(std::make_pair(key, std::make_tuple(context.str(), true, msg->sender())));
141 });141 });
142 142
143 auto reply = dbus::Message::make_method_return(msg);143 auto reply = dbus::Message::make_method_return(msg);
144 reply->writer() << std::make_tuple(op, uuid);144 reply->writer() << std::make_tuple(op, uuid);
145145
@@ -161,20 +161,24 @@
161 std::string uuid;161 std::string uuid;
162 msg->reader() >> uuid;162 msg->reader() >> uuid;
163163
164 auto key = uuid_player_map.at(uuid);164 // Make sure we don't try to do a lookup if the map is empty
165 if (!uuid_player_map.empty())
166 {
167 const auto key = uuid_player_map.at(uuid);
165168
166 if (player_owner_map.count(key) != 0) {169 if (player_owner_map.count(key) != 0) {
167 auto info = player_owner_map.at(key);170 auto info = player_owner_map.at(key);
168 // Check if session is attached(1) and that the detachment171 // Check if session is attached(1) and that the detachment
169 // request comes from the same peer(2) that created the session.172 // request comes from the same peer(2) that created the session.
170 if (std::get<1>(info) && (std::get<2>(info) == msg->sender())) { // Player is attached173 if (std::get<1>(info) && (std::get<2>(info) == msg->sender())) { // Player is attached
171 std::get<1>(info) = false; // Detached174 std::get<1>(info) = false; // Detached
172 std::get<2>(info).clear(); // Clear registered sender/peer175 std::get<2>(info).clear(); // Clear registered sender/peer
173 auto player = configuration.player_store->player_for_key(key);176 auto player = configuration.player_store->player_for_key(key);
174 player->lifetime().set(media::Player::Lifetime::resumable);177 player->lifetime().set(media::Player::Lifetime::resumable);
178 }
175 }179 }
176 }180 }
177 181
178 auto reply = dbus::Message::make_method_return(msg);182 auto reply = dbus::Message::make_method_return(msg);
179 impl->access_bus()->send(reply);183 impl->access_bus()->send(reply);
180184
@@ -256,7 +260,6 @@
256260
257 void handle_destroy_session(const core::dbus::Message::Ptr& msg)261 void handle_destroy_session(const core::dbus::Message::Ptr& msg)
258 {262 {
259
260 try263 try
261 {264 {
262 std::string uuid;265 std::string uuid;
@@ -445,9 +448,9 @@
445 // We keep a list of keys and their respective owners and states.448 // We keep a list of keys and their respective owners and states.
446 // value: (owner context, attached state, attached dbus name)449 // value: (owner context, attached state, attached dbus name)
447 std::map<media::Player::PlayerKey, std::tuple<std::string, bool, std::string>> player_owner_map;450 std::map<media::Player::PlayerKey, std::tuple<std::string, bool, std::string>> player_owner_map;
448 451
449 boost::uuids::random_generator gen;452 boost::uuids::random_generator gen;
450 453
451 // We expose the entire service as an MPRIS player.454 // We expose the entire service as an MPRIS player.
452 struct Exported455 struct Exported
453 {456 {
@@ -476,13 +479,7 @@
476479
477 static std::string service_name()480 static std::string service_name()
478 {481 {
479 static const bool export_to_indicator_sound_via_mpris482 return "org.mpris.MediaPlayer2.MediaHub";
480 {
481 core::posix::this_process::env::get("UBUNTU_MEDIA_HUB_EXPORT_TO_INDICATOR_VIA_MPRIS", "0") == "1"
482 };
483
484 return export_to_indicator_sound_via_mpris ? "org.mpris.MediaPlayer2.MediaHub" :
485 "hidden.org.mpris.MediaPlayer2.MediaHub";
486 }483 }
487484
488 explicit Exported(const dbus::Bus::Ptr& bus, const media::CoverArtResolver& cover_art_resolver)485 explicit Exported(const dbus::Bus::Ptr& bus, const media::CoverArtResolver& cover_art_resolver)
489486
=== modified file 'src/core/media/track.cpp'
--- src/core/media/track.cpp 2014-02-12 15:53:57 +0000
+++ src/core/media/track.cpp 2015-08-03 18:09:14 +0000
@@ -25,9 +25,10 @@
25struct media::Track::Private25struct media::Track::Private
26{26{
27 media::Track::Id id;27 media::Track::Id id;
28 media::Track::UriType uri;
28};29};
2930
30media::Track::Track(const media::Track::Id& id) : d(new Private{id})31media::Track::Track(const media::Track::Id& id) : d(new Private{id, std::string{}})
31{32{
32}33}
3334
@@ -39,3 +40,8 @@
39{40{
40 return d->id;41 return d->id;
41}42}
43
44const media::Track::UriType& media::Track::uri() const
45{
46 return d->uri;
47}
4248
=== modified file 'src/core/media/track_list_implementation.cpp'
--- src/core/media/track_list_implementation.cpp 2015-05-22 21:19:28 +0000
+++ src/core/media/track_list_implementation.cpp 2015-08-03 18:09:14 +0000
@@ -59,17 +59,19 @@
5959
60media::Track::UriType media::TrackListImplementation::query_uri_for_track(const media::Track::Id& id)60media::Track::UriType media::TrackListImplementation::query_uri_for_track(const media::Track::Id& id)
61{61{
62 auto it = d->meta_data_cache.find(id);62 const auto it = d->meta_data_cache.find(id);
6363
64 if (it == d->meta_data_cache.end())64 if (it == d->meta_data_cache.end())
65 return Track::UriType{};65 return Track::UriType{};
6666
67 //std::cout << "returning uri: " << std::get<0>(it->second) << std::endl;
68
67 return std::get<0>(it->second);69 return std::get<0>(it->second);
68}70}
6971
70media::Track::MetaData media::TrackListImplementation::query_meta_data_for_track(const media::Track::Id& id)72media::Track::MetaData media::TrackListImplementation::query_meta_data_for_track(const media::Track::Id& id)
71{73{
72 auto it = d->meta_data_cache.find(id);74 const auto it = d->meta_data_cache.find(id);
7375
74 if (it == d->meta_data_cache.end())76 if (it == d->meta_data_cache.end())
75 return Track::MetaData{};77 return Track::MetaData{};
@@ -87,10 +89,14 @@
87 std::stringstream ss; ss << d->object->path().as_string() << "/" << d->track_counter++;89 std::stringstream ss; ss << d->object->path().as_string() << "/" << d->track_counter++;
88 Track::Id id{ss.str()};90 Track::Id id{ss.str()};
8991
92 std::cout << "Adding Track::Id: " << id << std::endl;
93 std::cout << "\tURI: " << uri << std::endl;
94
90 auto result = tracks().update([this, id, position, make_current](TrackList::Container& container)95 auto result = tracks().update([this, id, position, make_current](TrackList::Container& container)
91 {96 {
92 auto it = std::find(container.begin(), container.end(), position);97 auto it = std::find(container.begin(), container.end(), position);
93 container.insert(it, id);98 container.insert(it, id);
99 std::cout << "container.size(): " << container.size() << std::endl;
94100
95 return true;101 return true;
96 });102 });
@@ -99,6 +105,8 @@
99 {105 {
100 if (d->meta_data_cache.count(id) == 0)106 if (d->meta_data_cache.count(id) == 0)
101 {107 {
108 // FIXME: This code seems to conflict badly when called multiple times in a row: causes segfaults
109#if 0
102 try {110 try {
103 d->meta_data_cache[id] = std::make_tuple(111 d->meta_data_cache[id] = std::make_tuple(
104 uri,112 uri,
@@ -106,6 +114,11 @@
106 } catch (const std::runtime_error &e) {114 } catch (const std::runtime_error &e) {
107 std::cerr << "Failed to retrieve metadata for track '" << uri << "' (" << e.what() << ")" << std::endl;115 std::cerr << "Failed to retrieve metadata for track '" << uri << "' (" << e.what() << ")" << std::endl;
108 }116 }
117#else
118 d->meta_data_cache[id] = std::make_tuple(
119 uri,
120 core::ubuntu::media::Track::MetaData{});
121#endif
109 } else122 } else
110 {123 {
111 std::get<0>(d->meta_data_cache[id]) = uri;124 std::get<0>(d->meta_data_cache[id]) = uri;
@@ -120,8 +133,14 @@
120 go_to(id, toggle_player_state);133 go_to(id, toggle_player_state);
121 }134 }
122135
136 // Signal to the client that the current track has changed for the first track added to the TrackList
137 if (tracks().get().size() == 1)
138 on_track_changed()(id);
139
140 std::cout << "Signaling that we just added track id: " << id << std::endl;
123 // Signal to the client that a track was added to the TrackList141 // Signal to the client that a track was added to the TrackList
124 on_track_added()(id);142 on_track_added()(id);
143 std::cout << "Signaled that we just added track id: " << id << std::endl;
125 }144 }
126}145}
127146
@@ -133,6 +152,8 @@
133 return true;152 return true;
134 });153 });
135154
155 reset_current_iterator_if_needed();
156
136 if (result)157 if (result)
137 {158 {
138 d->meta_data_cache.erase(id);159 d->meta_data_cache.erase(id);
@@ -155,8 +176,12 @@
155{176{
156 std::cout << __PRETTY_FUNCTION__ << std::endl;177 std::cout << __PRETTY_FUNCTION__ << std::endl;
157178
179 if (tracks().get().empty())
180 return;
181
158 auto result = tracks().update([this](TrackList::Container& container)182 auto result = tracks().update([this](TrackList::Container& container)
159 {183 {
184 // Save off the original TrackList ordering
160 d->original_tracklist.assign(container.begin(), container.end());185 d->original_tracklist.assign(container.begin(), container.end());
161 std::random_shuffle(container.begin(), container.end());186 std::random_shuffle(container.begin(), container.end());
162 return true;187 return true;
@@ -173,8 +198,12 @@
173{198{
174 std::cout << __PRETTY_FUNCTION__ << std::endl;199 std::cout << __PRETTY_FUNCTION__ << std::endl;
175200
201 if (tracks().get().empty() or d->original_tracklist.empty())
202 return;
203
176 auto result = tracks().update([this](TrackList::Container& container)204 auto result = tracks().update([this](TrackList::Container& container)
177 {205 {
206 // Restore the original TrackList ordering
178 container.assign(d->original_tracklist.begin(), d->original_tracklist.end());207 container.assign(d->original_tracklist.begin(), d->original_tracklist.end());
179 return true;208 return true;
180 });209 });
@@ -190,6 +219,9 @@
190{219{
191 std::cout << __PRETTY_FUNCTION__ << std::endl;220 std::cout << __PRETTY_FUNCTION__ << std::endl;
192221
222 // Make sure playback stops
223 on_end_of_tracklist()();
224
193 auto result = tracks().update([this](TrackList::Container& container)225 auto result = tracks().update([this](TrackList::Container& container)
194 {226 {
195 container.clear();227 container.clear();
@@ -198,5 +230,7 @@
198 return true;230 return true;
199 });231 });
200232
233 media::TrackListSkeleton::reset();
234
201 (void) result;235 (void) result;
202}236}
203237
=== modified file 'src/core/media/track_list_skeleton.cpp'
--- src/core/media/track_list_skeleton.cpp 2015-04-29 21:18:20 +0000
+++ src/core/media/track_list_skeleton.cpp 2015-08-03 18:09:14 +0000
@@ -60,6 +60,7 @@
60 {60 {
61 skeleton.signals.track_added,61 skeleton.signals.track_added,
62 skeleton.signals.track_removed,62 skeleton.signals.track_removed,
63 skeleton.signals.track_changed,
63 skeleton.signals.tracklist_replaced64 skeleton.signals.tracklist_replaced
64 }65 }
65 {66 {
@@ -70,15 +71,28 @@
70 media::Track::Id track;71 media::Track::Id track;
71 msg->reader() >> track;72 msg->reader() >> track;
7273
73 auto meta_data = impl->query_meta_data_for_track(track);74 const auto meta_data = impl->query_meta_data_for_track(track);
7475
75 auto reply = dbus::Message::make_method_return(msg);76 const auto reply = dbus::Message::make_method_return(msg);
76 reply->writer() << *meta_data;77 reply->writer() << *meta_data;
77 bus->send(reply);78 bus->send(reply);
78 }79 }
7980
81 void handle_get_tracks_uri(const core::dbus::Message::Ptr& msg)
82 {
83 media::Track::Id track;
84 msg->reader() >> track;
85
86 const auto uri = impl->query_uri_for_track(track);
87
88 const auto reply = dbus::Message::make_method_return(msg);
89 reply->writer() << uri;
90 bus->send(reply);
91 }
92
80 void handle_add_track_with_uri_at(const core::dbus::Message::Ptr& msg)93 void handle_add_track_with_uri_at(const core::dbus::Message::Ptr& msg)
81 {94 {
95 std::cout << "*** " << __PRETTY_FUNCTION__ << std::endl;
82 request_context_resolver->resolve_context_for_dbus_name_async(msg->sender(), [this, msg](const media::apparmor::ubuntu::Context& context)96 request_context_resolver->resolve_context_for_dbus_name_async(msg->sender(), [this, msg](const media::apparmor::ubuntu::Context& context)
83 {97 {
84 Track::UriType uri; media::Track::Id after; bool make_current;98 Track::UriType uri; media::Track::Id after; bool make_current;
@@ -90,7 +104,9 @@
90 auto reply = dbus::Message::make_method_return(msg);104 auto reply = dbus::Message::make_method_return(msg);
91 // Only add the track to the TrackList if it passes the apparmor permissions check105 // Only add the track to the TrackList if it passes the apparmor permissions check
92 if (std::get<0>(result))106 if (std::get<0>(result))
107 {
93 impl->add_track_with_uri_at(uri, after, make_current);108 impl->add_track_with_uri_at(uri, after, make_current);
109 }
94 else110 else
95 std::cerr << "Warning: Not adding track " << uri <<111 std::cerr << "Warning: Not adding track " << uri <<
96 " to TrackList because of inadequate client apparmor permissions." << std::endl;112 " to TrackList because of inadequate client apparmor permissions." << std::endl;
@@ -123,6 +139,14 @@
123 bus->send(reply);139 bus->send(reply);
124 }140 }
125141
142 void handle_reset(const core::dbus::Message::Ptr& msg)
143 {
144 impl->reset();
145
146 auto reply = dbus::Message::make_method_return(msg);
147 bus->send(reply);
148 }
149
126 media::TrackListSkeleton* impl;150 media::TrackListSkeleton* impl;
127 dbus::Bus::Ptr bus;151 dbus::Bus::Ptr bus;
128 dbus::Object::Ptr object;152 dbus::Object::Ptr object;
@@ -138,10 +162,12 @@
138 {162 {
139 typedef core::dbus::Signal<mpris::TrackList::Signals::TrackAdded, mpris::TrackList::Signals::TrackAdded::ArgumentType> DBusTrackAddedSignal;163 typedef core::dbus::Signal<mpris::TrackList::Signals::TrackAdded, mpris::TrackList::Signals::TrackAdded::ArgumentType> DBusTrackAddedSignal;
140 typedef core::dbus::Signal<mpris::TrackList::Signals::TrackRemoved, mpris::TrackList::Signals::TrackRemoved::ArgumentType> DBusTrackRemovedSignal;164 typedef core::dbus::Signal<mpris::TrackList::Signals::TrackRemoved, mpris::TrackList::Signals::TrackRemoved::ArgumentType> DBusTrackRemovedSignal;
165 typedef core::dbus::Signal<mpris::TrackList::Signals::TrackChanged, mpris::TrackList::Signals::TrackChanged::ArgumentType> DBusTrackChangedSignal;
141 typedef core::dbus::Signal<mpris::TrackList::Signals::TrackListReplaced, mpris::TrackList::Signals::TrackListReplaced::ArgumentType> DBusTrackListReplacedSignal;166 typedef core::dbus::Signal<mpris::TrackList::Signals::TrackListReplaced, mpris::TrackList::Signals::TrackListReplaced::ArgumentType> DBusTrackListReplacedSignal;
142167
143 Signals(const std::shared_ptr<DBusTrackAddedSignal>& remote_track_added,168 Signals(const std::shared_ptr<DBusTrackAddedSignal>& remote_track_added,
144 const std::shared_ptr<DBusTrackRemovedSignal>& remote_track_removed,169 const std::shared_ptr<DBusTrackRemovedSignal>& remote_track_removed,
170 const std::shared_ptr<DBusTrackChangedSignal>& remote_track_changed,
145 const std::shared_ptr<DBusTrackListReplacedSignal>& remote_track_list_replaced)171 const std::shared_ptr<DBusTrackListReplacedSignal>& remote_track_list_replaced)
146 {172 {
147 // Connect all of the MPRIS interface signals to be emitted over dbus173 // Connect all of the MPRIS interface signals to be emitted over dbus
@@ -155,6 +181,11 @@
155 remote_track_removed->emit(id);181 remote_track_removed->emit(id);
156 });182 });
157183
184 on_track_changed.connect([remote_track_changed](const media::Track::Id &id)
185 {
186 remote_track_changed->emit(id);
187 });
188
158 on_track_list_replaced.connect([remote_track_list_replaced](const media::TrackList::ContainerTrackIdTuple &tltuple)189 on_track_list_replaced.connect([remote_track_list_replaced](const media::TrackList::ContainerTrackIdTuple &tltuple)
159 {190 {
160 remote_track_list_replaced->emit(tltuple);191 remote_track_list_replaced->emit(tltuple);
@@ -163,9 +194,10 @@
163194
164 core::Signal<Track::Id> on_track_added;195 core::Signal<Track::Id> on_track_added;
165 core::Signal<Track::Id> on_track_removed;196 core::Signal<Track::Id> on_track_removed;
197 core::Signal<Track::Id> on_track_changed;
166 core::Signal<TrackList::ContainerTrackIdTuple> on_track_list_replaced;198 core::Signal<TrackList::ContainerTrackIdTuple> on_track_list_replaced;
167 core::Signal<Track::Id> on_track_changed;
168 core::Signal<std::pair<Track::Id, bool>> on_go_to_track;199 core::Signal<std::pair<Track::Id, bool>> on_go_to_track;
200 core::Signal<void> on_end_of_tracklist;
169 } signals;201 } signals;
170};202};
171203
@@ -179,6 +211,11 @@
179 std::ref(d),211 std::ref(d),
180 std::placeholders::_1));212 std::placeholders::_1));
181213
214 d->object->install_method_handler<mpris::TrackList::GetTracksUri>(
215 std::bind(&Private::handle_get_tracks_uri,
216 std::ref(d),
217 std::placeholders::_1));
218
182 d->object->install_method_handler<mpris::TrackList::AddTrack>(219 d->object->install_method_handler<mpris::TrackList::AddTrack>(
183 std::bind(&Private::handle_add_track_with_uri_at,220 std::bind(&Private::handle_add_track_with_uri_at,
184 std::ref(d),221 std::ref(d),
@@ -193,74 +230,182 @@
193 std::bind(&Private::handle_go_to,230 std::bind(&Private::handle_go_to,
194 std::ref(d),231 std::ref(d),
195 std::placeholders::_1));232 std::placeholders::_1));
233
234 d->object->install_method_handler<mpris::TrackList::Reset>(
235 std::bind(&Private::handle_reset,
236 std::ref(d),
237 std::placeholders::_1));
196}238}
197239
198media::TrackListSkeleton::~TrackListSkeleton()240media::TrackListSkeleton::~TrackListSkeleton()
199{241{
200}242}
201243
202bool media::TrackListSkeleton::has_next() const244bool media::TrackListSkeleton::has_next()
203{245{
204 const auto next_track = std::next(d->current_track);246 if (tracks().get().empty())
205 std::cout << "has_next track? " << (next_track != tracks().get().end() ? "yes" : "no") << std::endl;247 return false;
206 return next_track != tracks().get().end();248
249 const auto next_track = std::next(current_iterator());
250 return !is_last_track(next_track);
207}251}
208252
209bool media::TrackListSkeleton::has_previous() const253bool media::TrackListSkeleton::has_previous()
210{254{
255 if (tracks().get().empty())
256 return false;
257
211 // If we are looping over the entire list, then there is always a previous track258 // If we are looping over the entire list, then there is always a previous track
212 if (d->loop_status == media::Player::LoopStatus::playlist)259 if (d->loop_status == media::Player::LoopStatus::playlist)
213 return true;260 return true;
214261
215 std::cout << "has_previous track? " << (d->current_track != tracks().get().begin() ? "yes" : "no") << std::endl;262 return d->current_track != std::begin(tracks().get());
216 return d->current_track != tracks().get().begin();263}
264
265bool media::TrackListSkeleton::is_first_track(const ConstIterator &it)
266{
267 return it == std::begin(tracks().get());
268}
269
270bool media::TrackListSkeleton::is_last_track(const TrackList::ConstIterator &it)
271{
272 return it == std::end(tracks().get());
217}273}
218274
219media::Track::Id media::TrackListSkeleton::next()275media::Track::Id media::TrackListSkeleton::next()
220{276{
221 std::cout << __PRETTY_FUNCTION__ << std::endl;277 std::cout << __PRETTY_FUNCTION__ << std::endl;
222 if (tracks().get().empty())278 if (tracks().get().empty())
223 return *(d->current_track);279 return *(d->empty_iterator);
280
281 const auto next_track = std::next(current_iterator());
282 bool do_go_to_next_track = false;
283
284 // End of the track reached so loop around to the beginning of the track
285 if (d->loop_status == media::Player::LoopStatus::track)
286 {
287 std::cout << "Looping on the current track since LoopStatus is set to track" << std::endl;
288 do_go_to_next_track = true;
289 }
290 // End of the tracklist reached so loop around to the beginning of the tracklist
291 else if (d->loop_status == media::Player::LoopStatus::playlist && not has_next())
292 {
293 std::cout << "Looping on the tracklist since LoopStatus is set to playlist" << std::endl;
294 d->current_track = tracks().get().begin();
295 do_go_to_next_track = true;
296 }
297 else
298 {
299 // Next track is not the last track
300 if (not is_last_track(next_track))
301 {
302 std::cout << "Advancing to next track: " << *(next_track) << std::endl;
303 d->current_track = next_track;
304 do_go_to_next_track = true;
305 }
306 // At the end of the tracklist and not set to loop, so we stop advancing the tracklist
307 else
308 {
309 std::cout << "End of tracklist reached, not advancing to next since LoopStatus is set to none" << std::endl;
310 on_end_of_tracklist()();
311 }
312 }
313
314 if (do_go_to_next_track)
315 {
316 on_track_changed()(*(current_iterator()));
317 // Don't automatically call stop() and play() in player_implementation.cpp on_go_to_track()
318 // since this breaks video playback when using open_uri() (stop() and play() are unwanted in
319 // this scenario since the qtubuntu-media will handle this automatically)
320 const bool toggle_player_state = false;
321 const media::Track::Id id = *(current_iterator());
322 const std::pair<const media::Track::Id, bool> p = std::make_pair(id, toggle_player_state);
323 // Signal the PlayerImplementation to play the next track
324 on_go_to_track()(p);
325 }
326
327 return *(current_iterator());
328}
329
330media::Track::Id media::TrackListSkeleton::previous()
331{
332 std::cout << __PRETTY_FUNCTION__ << std::endl;
333 if (tracks().get().empty())
334 return *(d->empty_iterator);
335
336 bool do_go_to_previous_track = false;
224337
225 // Loop on the current track forever338 // Loop on the current track forever
226 if (d->loop_status == media::Player::LoopStatus::track)339 if (d->loop_status == media::Player::LoopStatus::track)
227 {340 {
228 std::cout << "Looping on the current track..." << std::endl;341 std::cout << "Looping on the current track..." << std::endl;
229 return *(d->current_track);342 do_go_to_previous_track = true;
230 }343 }
231 // Loop over the whole playlist and repeat344 // Loop over the whole playlist and repeat
232 else if (d->loop_status == media::Player::LoopStatus::playlist && !has_next())345 else if (d->loop_status == media::Player::LoopStatus::playlist && is_first_track(current_iterator()))
233 {346 {
234 std::cout << "Looping on the entire TrackList..." << std::endl;347 std::cout << "Looping on the entire TrackList..." << std::endl;
235 d->current_track = tracks().get().begin();348 d->current_track = std::prev(tracks().get().end());
236 return *(d->current_track);349 do_go_to_previous_track = true;
237 }350 }
238 else if (has_next())351 else
239 {352 {
240 // Keep returning the next track until the last track is reached353 // Current track is not the first track
241 d->current_track = std::next(d->current_track);354 if (not is_first_track(current_iterator()))
242 std::cout << *this << std::endl;355 {
243 }356 // Keep returning the previous track until the first track is reached
244357 d->current_track = std::prev(current_iterator());
245 return *(d->current_track);358 do_go_to_previous_track = true;
246}359 }
247360 // At the beginning of the tracklist and not set to loop, so we stop advancing the tracklist
248media::Track::Id media::TrackListSkeleton::previous()361 else
249{362 {
250 // TODO: Add logic to calculate the previous track363 std::cout << "Beginning of tracklist reached, not advancing to previous since LoopStatus is set to none" << std::endl;
251 return *(d->current_track);364 on_end_of_tracklist()();
365 }
366 }
367
368 if (do_go_to_previous_track)
369 {
370 on_track_changed()(*(current_iterator()));
371 // Don't automatically call stop() and play() in player_implementation.cpp on_go_to_track()
372 // since this breaks video playback when using open_uri() (stop() and play() are unwanted in
373 // this scenario since the qtubuntu-media will handle this automatically)
374 const bool toggle_player_state = false;
375 const media::Track::Id id = *(current_iterator());
376 const std::pair<const media::Track::Id, bool> p = std::make_pair(id, toggle_player_state);
377 on_go_to_track()(p);
378 }
379
380 return *(current_iterator());
252}381}
253382
254const media::Track::Id& media::TrackListSkeleton::current()383const media::Track::Id& media::TrackListSkeleton::current()
255{384{
385 return *(current_iterator());
386}
387
388const media::TrackList::ConstIterator& media::TrackListSkeleton::current_iterator()
389{
256 // Prevent the TrackList from sitting at the end which will cause390 // Prevent the TrackList from sitting at the end which will cause
257 // a segfault when calling current()391 // a segfault when calling current()
258 if (tracks().get().size() && (d->current_track == d->empty_iterator))392 if (tracks().get().size() && (d->current_track == d->empty_iterator))
393 {
394 std::cout << "Wrapping d->current_track back to begin()" << std::endl;
259 d->current_track = d->skeleton.properties.tracks->get().begin();395 d->current_track = d->skeleton.properties.tracks->get().begin();
396 }
260 else if (tracks().get().empty())397 else if (tracks().get().empty())
261 std::cerr << "TrackList is empty therefore there is no valid current track" << std::endl;398 std::cerr << "TrackList is empty therefore there is no valid current track" << std::endl;
262399
263 return *(d->current_track);400 return d->current_track;
401}
402
403void media::TrackListSkeleton::reset_current_iterator_if_needed()
404{
405 // If all tracks got removed then we need to keep a sane current
406 // iterator for further use.
407 if (tracks().get().empty())
408 d->current_track = d->empty_iterator;
264}409}
265410
266const core::Property<bool>& media::TrackListSkeleton::can_edit_tracks() const411const core::Property<bool>& media::TrackListSkeleton::can_edit_tracks() const
@@ -293,7 +438,18 @@
293 if (shuffle)438 if (shuffle)
294 shuffle_tracks();439 shuffle_tracks();
295 else440 else
441 {
442 // Save the current Track::Id of what's currently playing to restore after unshuffle
443 const media::Track::Id current_id = *(current_iterator());
444
296 unshuffle_tracks();445 unshuffle_tracks();
446
447 // Since we use assign() in unshuffle_tracks, which invalidates existing iterators, we need
448 // to make sure that current is pointing to the right place
449 auto it = std::find(tracks().get().begin(), tracks().get().end(), current_id);
450 if (it != tracks().get().end())
451 d->current_track = it;
452 }
297}453}
298454
299const core::Property<media::TrackList::Container>& media::TrackListSkeleton::tracks() const455const core::Property<media::TrackList::Container>& media::TrackListSkeleton::tracks() const
@@ -328,6 +484,11 @@
328 return d->signals.on_go_to_track;484 return d->signals.on_go_to_track;
329}485}
330486
487const core::Signal<void>& media::TrackListSkeleton::on_end_of_tracklist() const
488{
489 return d->signals.on_end_of_tracklist;
490}
491
331core::Signal<media::TrackList::ContainerTrackIdTuple>& media::TrackListSkeleton::on_track_list_replaced()492core::Signal<media::TrackList::ContainerTrackIdTuple>& media::TrackListSkeleton::on_track_list_replaced()
332{493{
333 return d->signals.on_track_list_replaced;494 return d->signals.on_track_list_replaced;
@@ -353,6 +514,17 @@
353 return d->signals.on_go_to_track;514 return d->signals.on_go_to_track;
354}515}
355516
517core::Signal<void>& media::TrackListSkeleton::on_end_of_tracklist()
518{
519 return d->signals.on_end_of_tracklist;
520}
521
522void media::TrackListSkeleton::reset()
523{
524 std::cout << __PRETTY_FUNCTION__ << std::endl;
525 d->current_track = d->empty_iterator;
526}
527
356// operator<< pretty prints the given TrackList to the given output stream.528// operator<< pretty prints the given TrackList to the given output stream.
357inline std::ostream& media::operator<<(std::ostream& out, const media::TrackList& tracklist)529inline std::ostream& media::operator<<(std::ostream& out, const media::TrackList& tracklist)
358{530{
359531
=== modified file 'src/core/media/track_list_skeleton.h'
--- src/core/media/track_list_skeleton.h 2015-04-29 21:18:20 +0000
+++ src/core/media/track_list_skeleton.h 2015-08-03 18:09:14 +0000
@@ -41,8 +41,8 @@
41 const core::ubuntu::media::apparmor::ubuntu::RequestAuthenticator::Ptr& request_authenticator);41 const core::ubuntu::media::apparmor::ubuntu::RequestAuthenticator::Ptr& request_authenticator);
42 ~TrackListSkeleton();42 ~TrackListSkeleton();
4343
44 bool has_next() const;44 bool has_next();
45 bool has_previous() const;45 bool has_previous();
46 Track::Id next();46 Track::Id next();
47 Track::Id previous();47 Track::Id previous();
48 const Track::Id& current();48 const Track::Id& current();
@@ -52,10 +52,13 @@
5252
53 const core::Signal<ContainerTrackIdTuple>& on_track_list_replaced() const;53 const core::Signal<ContainerTrackIdTuple>& on_track_list_replaced() const;
54 const core::Signal<Track::Id>& on_track_added() const;54 const core::Signal<Track::Id>& on_track_added() const;
55 core::Signal<Track::Id>& on_track_added();
55 const core::Signal<Track::Id>& on_track_removed() const;56 const core::Signal<Track::Id>& on_track_removed() const;
56 const core::Signal<Track::Id>& on_track_changed() const;57 const core::Signal<Track::Id>& on_track_changed() const;
57 const core::Signal<std::pair<Track::Id, bool>>& on_go_to_track() const;58 const core::Signal<std::pair<Track::Id, bool>>& on_go_to_track() const;
58 core::Signal<std::pair<Track::Id, bool>>& on_go_to_track();59 core::Signal<std::pair<Track::Id, bool>>& on_go_to_track();
60 const core::Signal<void>& on_end_of_tracklist() const;
61 core::Signal<void>& on_end_of_tracklist();
59 core::Signal<Track::Id>& on_track_removed();62 core::Signal<Track::Id>& on_track_removed();
6063
61 core::Property<Container>& tracks();64 core::Property<Container>& tracks();
@@ -67,12 +70,18 @@
67 void on_shuffle_changed(bool shuffle);70 void on_shuffle_changed(bool shuffle);
6871
69protected:72protected:
73 inline bool is_first_track(const ConstIterator &it);
74 inline bool is_last_track(const ConstIterator &it);
75 inline const TrackList::ConstIterator& current_iterator();
76 void reset_current_iterator_if_needed();
77
70 core::Property<bool>& can_edit_tracks();78 core::Property<bool>& can_edit_tracks();
7179
72 core::Signal<ContainerTrackIdTuple>& on_track_list_replaced();80 core::Signal<ContainerTrackIdTuple>& on_track_list_replaced();
73 core::Signal<Track::Id>& on_track_added();
74 core::Signal<Track::Id>& on_track_changed();81 core::Signal<Track::Id>& on_track_changed();
7582
83 void reset();
84
76private:85private:
77 struct Private;86 struct Private;
78 std::unique_ptr<Private> d;87 std::unique_ptr<Private> d;
7988
=== modified file 'src/core/media/track_list_stub.cpp'
--- src/core/media/track_list_stub.cpp 2015-04-29 21:18:20 +0000
+++ src/core/media/track_list_stub.cpp 2015-08-03 18:09:14 +0000
@@ -48,7 +48,14 @@
48 parent(parent),48 parent(parent),
49 object(object),49 object(object),
50 can_edit_tracks(object->get_property<mpris::TrackList::Properties::CanEditTracks>()),50 can_edit_tracks(object->get_property<mpris::TrackList::Properties::CanEditTracks>()),
51 tracks(object->get_property<mpris::TrackList::Properties::Tracks>())51 tracks(object->get_property<mpris::TrackList::Properties::Tracks>()),
52 signals
53 {
54 object->get_signal<mpris::TrackList::Signals::TrackAdded>(),
55 object->get_signal<mpris::TrackList::Signals::TrackRemoved>(),
56 object->get_signal<mpris::TrackList::Signals::TrackListReplaced>(),
57 object->get_signal<mpris::TrackList::Signals::TrackChanged>()
58 }
52 {59 {
53 }60 }
5461
@@ -59,11 +66,70 @@
59 std::shared_ptr<core::dbus::Property<mpris::TrackList::Properties::CanEditTracks>> can_edit_tracks;66 std::shared_ptr<core::dbus::Property<mpris::TrackList::Properties::CanEditTracks>> can_edit_tracks;
60 std::shared_ptr<core::dbus::Property<mpris::TrackList::Properties::Tracks>> tracks;67 std::shared_ptr<core::dbus::Property<mpris::TrackList::Properties::Tracks>> tracks;
6168
62 core::Signal<media::TrackList::ContainerTrackIdTuple> on_track_list_replaced;69
63 core::Signal<Track::Id> on_track_added;70 struct Signals
64 core::Signal<Track::Id> on_track_removed;71 {
65 core::Signal<Track::Id> on_track_changed;72 typedef core::dbus::Signal<mpris::TrackList::Signals::TrackAdded, mpris::TrackList::Signals::TrackAdded::ArgumentType> DBusTrackAddedSignal;
66 core::Signal<std::pair<Track::Id, bool>> on_go_to_track;73 typedef core::dbus::Signal<mpris::TrackList::Signals::TrackRemoved, mpris::TrackList::Signals::TrackRemoved::ArgumentType> DBusTrackRemovedSignal;
74 typedef core::dbus::Signal<mpris::TrackList::Signals::TrackListReplaced, mpris::TrackList::Signals::TrackListReplaced::ArgumentType> DBusTrackListReplacedSignal;
75 typedef core::dbus::Signal<mpris::TrackList::Signals::TrackChanged, mpris::TrackList::Signals::TrackChanged::ArgumentType> DBusTrackChangedSignal;
76
77 Signals(const std::shared_ptr<DBusTrackAddedSignal>& track_added,
78 const std::shared_ptr<DBusTrackRemovedSignal>& track_removed,
79 const std::shared_ptr<DBusTrackListReplacedSignal>& track_list_replaced,
80 const std::shared_ptr<DBusTrackChangedSignal>& track_changed)
81 : on_track_added(),
82 on_track_removed(),
83 on_track_list_replaced(),
84 on_track_changed(),
85 dbus
86 {
87 track_added,
88 track_removed,
89 track_list_replaced,
90 track_changed,
91 }
92 {
93 dbus.on_track_added->connect([this](const Track::Id& id)
94 {
95 std::cout << "OnTrackAdded signal arrived via the bus." << std::endl;
96 on_track_added(id);
97 });
98
99 dbus.on_track_removed->connect([this](const Track::Id& id)
100 {
101 std::cout << "OnTrackRemoved signal arrived via the bus." << std::endl;
102 on_track_removed(id);
103 });
104
105 dbus.on_track_list_replaced->connect([this](const media::TrackList::ContainerTrackIdTuple& list)
106 {
107 std::cout << "OnTrackListRemoved signal arrived via the bus." << std::endl;
108 on_track_list_replaced(list);
109 });
110
111 dbus.on_track_changed->connect([this](const Track::Id& id)
112 {
113 std::cout << "OnTrackChanged signal arrived via the bus." << std::endl;
114 on_track_changed(id);
115 });
116 }
117
118 core::Signal<Track::Id> on_track_added;
119 core::Signal<Track::Id> on_track_removed;
120 core::Signal<media::TrackList::ContainerTrackIdTuple> on_track_list_replaced;
121 core::Signal<Track::Id> on_track_changed;
122 core::Signal<std::pair<Track::Id, bool>> on_go_to_track;
123 core::Signal<void> on_end_of_tracklist;
124
125 struct DBus
126 {
127 std::shared_ptr<DBusTrackAddedSignal> on_track_added;
128 std::shared_ptr<DBusTrackRemovedSignal> on_track_removed;
129 std::shared_ptr<DBusTrackListReplacedSignal> on_track_list_replaced;
130 std::shared_ptr<DBusTrackChangedSignal> on_track_changed;
131 } dbus;
132 } signals;
67};133};
68134
69media::TrackListStub::TrackListStub(135media::TrackListStub::TrackListStub(
@@ -104,6 +170,18 @@
104 return md;170 return md;
105}171}
106172
173media::Track::UriType media::TrackListStub::query_uri_for_track(const media::Track::Id& id)
174{
175 auto op = d->object->invoke_method_synchronously<
176 mpris::TrackList::GetTracksUri,
177 std::string>(id);
178
179 if (op.is_error())
180 throw std::runtime_error("Problem querying track for uri: " + op.error());
181
182 return op.value();
183}
184
107void media::TrackListStub::add_track_with_uri_at(185void media::TrackListStub::add_track_with_uri_at(
108 const media::Track::UriType& uri,186 const media::Track::UriType& uri,
109 const media::Track::Id& id,187 const media::Track::Id& id,
@@ -161,33 +239,38 @@
161239
162void media::TrackListStub::reset()240void media::TrackListStub::reset()
163{241{
164 std::cerr << "reset() does nothing from the client side" << std::endl;242 auto op = d->object->invoke_method_synchronously<mpris::TrackList::Reset, void>();
243
244 if (op.is_error())
245 throw std::runtime_error("Problem resetting tracklist: " + op.error());
165}246}
166247
167const core::Signal<media::TrackList::ContainerTrackIdTuple>& media::TrackListStub::on_track_list_replaced() const248const core::Signal<media::TrackList::ContainerTrackIdTuple>& media::TrackListStub::on_track_list_replaced() const
168{249{
169 std::cout << "Signal on_track_list_replaced arrived via the bus" << std::endl;250 return d->signals.on_track_list_replaced;
170 return d->on_track_list_replaced;
171}251}
172252
173const core::Signal<media::Track::Id>& media::TrackListStub::on_track_added() const253const core::Signal<media::Track::Id>& media::TrackListStub::on_track_added() const
174{254{
175 std::cout << "Signal on_track_added arrived via the bus" << std::endl;255 return d->signals.on_track_added;
176 return d->on_track_added;
177}256}
178257
179const core::Signal<media::Track::Id>& media::TrackListStub::on_track_removed() const258const core::Signal<media::Track::Id>& media::TrackListStub::on_track_removed() const
180{259{
181 std::cout << "Signal on_track_removed arrived via the bus" << std::endl;260 return d->signals.on_track_removed;
182 return d->on_track_removed;
183}261}
184262
185const core::Signal<media::Track::Id>& media::TrackListStub::on_track_changed() const263const core::Signal<media::Track::Id>& media::TrackListStub::on_track_changed() const
186{264{
187 return d->on_track_changed;265 return d->signals.on_track_changed;
188}266}
189267
190const core::Signal<std::pair<media::Track::Id, bool>>& media::TrackListStub::on_go_to_track() const268const core::Signal<std::pair<media::Track::Id, bool>>& media::TrackListStub::on_go_to_track() const
191{269{
192 return d->on_go_to_track;270 return d->signals.on_go_to_track;
271}
272
273const core::Signal<void>& media::TrackListStub::on_end_of_tracklist() const
274{
275 return d->signals.on_end_of_tracklist;
193}276}
194277
=== modified file 'src/core/media/track_list_stub.h'
--- src/core/media/track_list_stub.h 2015-04-29 21:18:20 +0000
+++ src/core/media/track_list_stub.h 2015-08-03 18:09:14 +0000
@@ -45,6 +45,7 @@
45 const core::Property<Container>& tracks() const;45 const core::Property<Container>& tracks() const;
4646
47 Track::MetaData query_meta_data_for_track(const Track::Id& id);47 Track::MetaData query_meta_data_for_track(const Track::Id& id);
48 Track::UriType query_uri_for_track(const Track::Id& id);
4849
49 void add_track_with_uri_at(const Track::UriType& uri, const Track::Id& position, bool make_current);50 void add_track_with_uri_at(const Track::UriType& uri, const Track::Id& position, bool make_current);
50 void remove_track(const Track::Id& id);51 void remove_track(const Track::Id& id);
@@ -64,6 +65,7 @@
64 const core::Signal<Track::Id>& on_track_removed() const;65 const core::Signal<Track::Id>& on_track_removed() const;
65 const core::Signal<Track::Id>& on_track_changed() const;66 const core::Signal<Track::Id>& on_track_changed() const;
66 const core::Signal<std::pair<Track::Id, bool>>& on_go_to_track() const;67 const core::Signal<std::pair<Track::Id, bool>>& on_go_to_track() const;
68 const core::Signal<void>& on_end_of_tracklist() const;
6769
68private:70private:
69 struct Private;71 struct Private;

Subscribers

People subscribed via source and target branches

to all changes: