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