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