Merge lp:~phablet-team/media-hub/bg-playlists-vivid into lp:media-hub
- bg-playlists-vivid
- Merge into trunk
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 |
Related bugs: |
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; |