Merge lp:~phablet-team/media-hub/fix-1538703 into lp:media-hub
- fix-1538703
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~phablet-team/media-hub/fix-1538703 |
Merge into: | lp:media-hub |
Diff against target: |
342 lines (+133/-18) 9 files modified
debian/libmedia-hub-doc.install (+1/-1) doc/CMakeLists.txt (+2/-2) include/core/media/service.h (+0/-3) src/core/media/player_configuration.h (+15/-0) src/core/media/player_implementation.cpp (+63/-6) src/core/media/player_skeleton.h (+3/-1) src/core/media/service_implementation.cpp (+3/-3) src/core/media/service_skeleton.cpp (+35/-2) src/core/media/service_skeleton.h (+11/-0) |
To merge this branch: | bzr merge lp:~phablet-team/media-hub/fix-1538703 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alfonso Sanchez-Beato | Needs Fixing | ||
Review via email:
|
This proposal supersedes a proposal from 2016-03-28.
This proposal has been superseded by a proposal from 2016-04-15.
Commit message
A rewrite of how the current player is set which is what the MPRIS control interface actively uses.
Description of the change
A rewrite of how the current player is set which is what the MPRIS control interface actively uses.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote : Posted in a previous version of this proposal | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Jim Hodapp (jhodapp) wrote : Posted in a previous version of this proposal | # |
> Looks good, but maybe we need to call update_
> complete track lists? Which is done with AddTrack(s) DBus calls.
Can you explain more why you think we need to do this? I don't see any gap that this would fix.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Jim Hodapp (jhodapp) wrote : Posted in a previous version of this proposal | # |
Addressed review comments.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote : Posted in a previous version of this proposal | # |
LGTM
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote : | # |
So I have just seen that Jim modified service.h too to add reset_current_
I think that changing PlayerSkeleton so player_service is a pointer to ServiceSkeleton, and implementing these functions only in ServiceSkeleton should work. We will make sure the DBus interface is not contaminated and we remove the need for dummy implementations in ServiceStub and ServiceImplemen
@Konrad maybe we con wait for Jim if you do not feel comfortable with this change.
Finally, I appreciate the long description in the last commit message, but I think most of it should move to a comment inside the code so it is more easily found.
The change looks good beside this issue with service.h.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Konrad Zapałowicz (kzapalowicz) wrote : | # |
Thanks for the review and I will try to make the changes that you suggest. Either I'm successful or not and the Jim will take over when he is back however before that happens I will get my hands dirty :)
- 184. By Konrad Zapałowicz
-
Revert change which was reviewed as bad
- 185. By Konrad Zapałowicz
-
Fix resetting the current player on disconnection and interface pollution
This commit changes:
* The condition under which the current player is reset. Originally
this happened only for multimedia role however this turned out to be
faulty and trigger an unwanted behavior [1]. This change allows the
reset to happen only when it is a multimedia role [already there] and
the player is the current player i.e. the Player instance that
disconnected was the last player to play audio/video [added].In order to achieve this the ServiceSkeleton class has been extended
with a new function to return the current player.* Reduces the pollution of the Service interface, which has been
introduced in rev 152 & 153, by moving the added functions to the
ServiceSkeleton class. This is because the Service interface should
be used only for DBus exported stuff.1.
The issue as described by jibel was: I see 1 issue with the silo,
play a video, open the music app (video will pause), enqueue several
tracks and start playing (verify that MPRIS switched to music app),
reveal the spread and close the mediaplayer the controls switch to the
mediaplayer but the music continues playing then if you switch back to
the music app, the controls are still for the mediaplayer even if music
app is in the foreground and music is playign. I've to pause/play the
track in the music app for the music app to take control of mpris. - 186. By Jim Hodapp
-
Pass a Service* instead of ServiceSkeleton* to avoid weird inheritance segfault
Unmerged revisions
- 186. By Jim Hodapp
-
Pass a Service* instead of ServiceSkeleton* to avoid weird inheritance segfault
Preview Diff
1 | === modified file 'debian/libmedia-hub-doc.install' |
2 | --- debian/libmedia-hub-doc.install 2014-03-06 22:51:51 +0000 |
3 | +++ debian/libmedia-hub-doc.install 2016-04-15 18:49:23 +0000 |
4 | @@ -1,1 +1,1 @@ |
5 | -usr/share/doc/music-hub/html |
6 | +usr/share/doc/media-hub/html |
7 | |
8 | === modified file 'doc/CMakeLists.txt' |
9 | --- doc/CMakeLists.txt 2013-08-14 18:05:23 +0000 |
10 | +++ doc/CMakeLists.txt 2016-04-15 18:49:23 +0000 |
11 | @@ -26,5 +26,5 @@ |
12 | COMMENT "Generating API documentation with Doxygen" VERBATIM) |
13 | install( |
14 | DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html |
15 | - DESTINATION share/doc/music-hub) |
16 | -endif(DOXYGEN_FOUND) |
17 | \ No newline at end of file |
18 | + DESTINATION share/doc/media-hub) |
19 | +endif(DOXYGEN_FOUND) |
20 | |
21 | === modified file 'include/core/media/service.h' |
22 | --- include/core/media/service.h 2015-09-08 20:03:56 +0000 |
23 | +++ include/core/media/service.h 2016-04-15 18:49:23 +0000 |
24 | @@ -60,9 +60,6 @@ |
25 | /** @brief Resumes a fixed-name session directly by player key. */ |
26 | virtual std::shared_ptr<Player> resume_session(Player::PlayerKey) = 0; |
27 | |
28 | - /** @brief Sets the current player that the MPRIS interface will control */ |
29 | - virtual void set_current_player(Player::PlayerKey) = 0; |
30 | - |
31 | /** @brief Pauses sessions other than the supplied one. */ |
32 | virtual void pause_other_sessions(Player::PlayerKey) = 0; |
33 | |
34 | |
35 | === modified file 'src/core/media/player_configuration.h' |
36 | --- src/core/media/player_configuration.h 2015-04-17 16:44:30 +0000 |
37 | +++ src/core/media/player_configuration.h 2016-04-15 18:49:23 +0000 |
38 | @@ -19,10 +19,23 @@ |
39 | #define CORE_UBUNTU_MEDIA_PLAYER_CLIENT_CONFIGURATION_H_ |
40 | |
41 | #include <core/media/player.h> |
42 | +#include <core/media/service.h> |
43 | |
44 | #include <core/dbus/bus.h> |
45 | #include <core/dbus/object.h> |
46 | |
47 | + |
48 | +namespace core |
49 | +{ |
50 | +namespace ubuntu |
51 | +{ |
52 | +namespace media |
53 | +{ |
54 | +class ServiceSkeleton; |
55 | +} |
56 | +} |
57 | +} |
58 | + |
59 | // Our internal structure for handing down parameters from the skeleton |
60 | // to the implementation in a way that is opaque to the client. |
61 | struct core::ubuntu::media::Player::Configuration |
62 | @@ -35,6 +48,8 @@ |
63 | std::shared_ptr<core::dbus::Service> service; |
64 | // The actual session object representing a player instance. |
65 | std::shared_ptr<core::dbus::Object> session; |
66 | + // The Service instance that manages Player instances |
67 | + core::ubuntu::media::ServiceSkeleton* player_service; |
68 | }; |
69 | |
70 | #endif // CORE_UBUNTU_MEDIA_PLAYER_CLIENT_CONFIGURATION_H_ |
71 | |
72 | === modified file 'src/core/media/player_implementation.cpp' |
73 | --- src/core/media/player_implementation.cpp 2016-02-19 16:14:42 +0000 |
74 | +++ src/core/media/player_implementation.cpp 2016-04-15 18:49:23 +0000 |
75 | @@ -17,7 +17,10 @@ |
76 | * Jim Hodapp <jim.hodapp@canonical.com> |
77 | */ |
78 | |
79 | +#include <core/media/service.h> |
80 | + |
81 | #include "player_implementation.h" |
82 | +#include "service_skeleton.h" |
83 | #include "util/timeout.h" |
84 | |
85 | #include <unistd.h> |
86 | @@ -302,14 +305,14 @@ |
87 | } |
88 | } |
89 | |
90 | - void update_mpris_properties(void) |
91 | + void update_mpris_properties() |
92 | { |
93 | - bool has_previous = track_list->has_previous() |
94 | + const bool has_previous = track_list->has_previous() |
95 | or parent->Parent::loop_status() != Player::LoopStatus::none; |
96 | - bool has_next = track_list->has_next() |
97 | + const bool has_next = track_list->has_next() |
98 | or parent->Parent::loop_status() != Player::LoopStatus::none; |
99 | - auto n_tracks = track_list->tracks()->size(); |
100 | - bool has_tracks = (n_tracks > 0) ? true : false; |
101 | + const auto n_tracks = track_list->tracks()->size(); |
102 | + const bool has_tracks = (n_tracks > 0) ? true : false; |
103 | |
104 | std::cout << "Updating MPRIS TrackList properties" |
105 | << "; Tracks: " << n_tracks |
106 | @@ -323,6 +326,35 @@ |
107 | parent->can_go_next().set(has_next); |
108 | } |
109 | |
110 | + bool update_current_player(const media::Player::PlayerKey& key) |
111 | + { |
112 | + if (not config.parent.player_service) |
113 | + return false; |
114 | + |
115 | + config.parent.player_service->set_current_player(key); |
116 | + return true; |
117 | + } |
118 | + |
119 | + // Utility to hide the complexity of getting the ptr to current player |
120 | + bool is_current_player(const media::PlayerImplementation<Parent> *p) const |
121 | + { |
122 | + return p == config.parent.player_service->get_current_player().get(); |
123 | + } |
124 | + |
125 | + bool is_multimedia_role() const |
126 | + { |
127 | + return config.parent.player_service->is_multimedia_role(); |
128 | + } |
129 | + |
130 | + bool reset_current_player() |
131 | + { |
132 | + if (not config.parent.player_service) |
133 | + return false; |
134 | + |
135 | + config.parent.player_service->reset_current_player(); |
136 | + return true; |
137 | + } |
138 | + |
139 | // Our link back to our parent. |
140 | media::PlayerImplementation<Parent>* parent; |
141 | // We just store the parameters passed on construction. |
142 | @@ -479,6 +511,20 @@ |
143 | // are cleared |
144 | d->clear_wakelocks(); |
145 | d->track_list->reset(); |
146 | + |
147 | + // Here it is decided if it is good to reset the current player. The |
148 | + // conditions to do so are very simple. It must be a multimedia role |
149 | + // and the Player that disconnected must be the last player to play |
150 | + // audio/video. |
151 | + if (d->is_multimedia_role() && d->is_current_player(this)) |
152 | + { |
153 | + // This is not a fatal error but merely |
154 | + // a warning that should be logged |
155 | + if (not d->reset_current_player()) |
156 | + std::cerr << "Failed to reset current player in " |
157 | + << __PRETTY_FUNCTION__ << std::endl; |
158 | + } |
159 | + |
160 | // And tell the outside world that the client has gone away |
161 | d->on_client_disconnected(); |
162 | }); |
163 | @@ -688,7 +734,8 @@ |
164 | d->track_list->reset(); |
165 | |
166 | // If empty uri, give the same meaning as QMediaPlayer::setMedia("") |
167 | - if (uri.empty()) { |
168 | + if (uri.empty()) |
169 | + { |
170 | cout << __PRETTY_FUNCTION__ << ": resetting current media" << endl; |
171 | return true; |
172 | } |
173 | @@ -698,6 +745,7 @@ |
174 | // Don't set new track as the current track to play since we're calling open_resource_for_uri above |
175 | static const bool make_current = false; |
176 | d->track_list->add_track_with_uri_at(uri, media::TrackList::after_empty_track(), make_current); |
177 | + |
178 | return ret; |
179 | } |
180 | |
181 | @@ -722,6 +770,15 @@ |
182 | template<typename Parent> |
183 | void media::PlayerImplementation<Parent>::play() |
184 | { |
185 | + if (Parent::audio_stream_role() == media::Player::AudioStreamRole::multimedia) |
186 | + { |
187 | + std::cout << "==== Updating the current player from " << __PRETTY_FUNCTION__ << std::endl; |
188 | + // This player will begin playing so make sure it's the current player. If |
189 | + // this operation fails it is not a fatal condition but should be logged |
190 | + if (not d->update_current_player(d->config.key)) |
191 | + std::cerr << "Failed to update current player in " << __PRETTY_FUNCTION__ << std::endl; |
192 | + } |
193 | + |
194 | d->engine->play(); |
195 | } |
196 | |
197 | |
198 | === modified file 'src/core/media/player_skeleton.h' |
199 | --- src/core/media/player_skeleton.h 2015-04-17 15:13:56 +0000 |
200 | +++ src/core/media/player_skeleton.h 2016-04-15 18:49:23 +0000 |
201 | @@ -43,7 +43,7 @@ |
202 | struct ExternalServices; |
203 | } |
204 | |
205 | -class Service; |
206 | +class ServiceSkeleton; |
207 | |
208 | class PlayerSkeleton : public core::ubuntu::media::Player |
209 | { |
210 | @@ -57,6 +57,8 @@ |
211 | std::shared_ptr<core::dbus::Service> service; |
212 | // The session object that we want to expose the skeleton upon. |
213 | std::shared_ptr<core::dbus::Object> session; |
214 | + // The ServiceSkeleton instance that manages Player instances |
215 | + core::ubuntu::media::ServiceSkeleton* player_service; |
216 | // Our functional dependencies. |
217 | apparmor::ubuntu::RequestContextResolver::Ptr request_context_resolver; |
218 | apparmor::ubuntu::RequestAuthenticator::Ptr request_authenticator; |
219 | |
220 | === modified file 'src/core/media/service_implementation.cpp' |
221 | --- src/core/media/service_implementation.cpp 2016-03-02 18:32:46 +0000 |
222 | +++ src/core/media/service_implementation.cpp 2016-04-15 18:49:23 +0000 |
223 | @@ -185,11 +185,13 @@ |
224 | auto player = std::make_shared<media::PlayerImplementation<media::PlayerSkeleton>> |
225 | (media::PlayerImplementation<media::PlayerSkeleton>::Configuration |
226 | { |
227 | + // Derive a PlayerSkeleton-specific Configuration based on Player::Configuration |
228 | media::PlayerSkeleton::Configuration |
229 | { |
230 | conf.bus, |
231 | conf.service, |
232 | conf.session, |
233 | + conf.player_service, |
234 | d->request_context_resolver, |
235 | d->request_authenticator |
236 | }, |
237 | @@ -259,13 +261,11 @@ |
238 | |
239 | void media::ServiceImplementation::set_current_player(Player::PlayerKey) |
240 | { |
241 | - // no impl |
242 | + // no impl |
243 | } |
244 | |
245 | void media::ServiceImplementation::pause_other_sessions(media::Player::PlayerKey key) |
246 | { |
247 | - std::cout << __PRETTY_FUNCTION__ << std::endl; |
248 | - |
249 | if (not d->configuration.player_store->has_player_for_key(key)) |
250 | { |
251 | cerr << "Could not find Player by key: " << key << endl; |
252 | |
253 | === modified file 'src/core/media/service_skeleton.cpp' |
254 | --- src/core/media/service_skeleton.cpp 2016-03-02 18:32:46 +0000 |
255 | +++ src/core/media/service_skeleton.cpp 2016-04-15 18:49:23 +0000 |
256 | @@ -131,7 +131,8 @@ |
257 | key, |
258 | impl->access_bus(), |
259 | impl->access_service(), |
260 | - impl->access_service()->add_object_for_path(op) |
261 | + impl->access_service()->add_object_for_path(op), |
262 | + impl |
263 | }; |
264 | |
265 | cout << "Session created by request of: " << msg->sender() |
266 | @@ -366,7 +367,8 @@ |
267 | key, |
268 | impl->access_bus(), |
269 | impl->access_service(), |
270 | - impl->access_service()->add_object_for_path(op) |
271 | + impl->access_service()->add_object_for_path(op), |
272 | + impl |
273 | }; |
274 | |
275 | auto session = impl->create_session(config); |
276 | @@ -787,6 +789,22 @@ |
277 | std::cout << __PRETTY_FUNCTION__ << std::endl; |
278 | // And announce that we can no longer be controlled. |
279 | player.properties.can_control->set(false); |
280 | + player.properties.can_play->set(false); |
281 | + player.properties.can_pause->set(false); |
282 | + player.properties.can_go_previous->set(false); |
283 | + player.properties.can_go_next->set(false); |
284 | + |
285 | + // Reset to null event connections |
286 | + connections.seeked_to = the_empty_signal.connect([](){}); |
287 | + connections.duration_changed = the_empty_signal.connect([](){}); |
288 | + connections.position_changed = the_empty_signal.connect([](){}); |
289 | + connections.playback_status_changed = the_empty_signal.connect([](){}); |
290 | + connections.loop_status_changed = the_empty_signal.connect([](){}); |
291 | + connections.can_play_changed = the_empty_signal.connect([](){}); |
292 | + connections.can_pause_changed = the_empty_signal.connect([](){}); |
293 | + connections.can_go_previous_changed = the_empty_signal.connect([](){}); |
294 | + connections.can_go_next_changed = the_empty_signal.connect([](){}); |
295 | + |
296 | current_player.reset(); |
297 | } |
298 | |
299 | @@ -901,6 +919,21 @@ |
300 | d->exported.set_current_player(player); |
301 | } |
302 | |
303 | +bool media::ServiceSkeleton::is_multimedia_role() const |
304 | +{ |
305 | + return d->exported.is_multimedia_role(); |
306 | +} |
307 | + |
308 | +std::shared_ptr<media::Player> media::ServiceSkeleton::get_current_player() const |
309 | +{ |
310 | + return d->exported.current_player.lock(); |
311 | +} |
312 | + |
313 | +void media::ServiceSkeleton::reset_current_player() |
314 | +{ |
315 | + d->exported.reset_current_player(); |
316 | +} |
317 | + |
318 | void media::ServiceSkeleton::pause_other_sessions(media::Player::PlayerKey key) |
319 | { |
320 | d->configuration.impl->pause_other_sessions(key); |
321 | |
322 | === modified file 'src/core/media/service_skeleton.h' |
323 | --- src/core/media/service_skeleton.h 2015-09-08 20:03:56 +0000 |
324 | +++ src/core/media/service_skeleton.h 2016-04-15 18:49:23 +0000 |
325 | @@ -60,6 +60,17 @@ |
326 | std::shared_ptr<Player> create_fixed_session(const std::string& name, const Player::Configuration&); |
327 | std::shared_ptr<Player> resume_session(Player::PlayerKey); |
328 | void set_current_player(Player::PlayerKey key); |
329 | + |
330 | + /** @brief returns true for multimedia role */ |
331 | + bool is_multimedia_role() const; |
332 | + |
333 | + /** @brief gets the current player controlled by MRIS */ |
334 | + std::shared_ptr<Player> get_current_player() const; |
335 | + |
336 | + /** @detail Resets the current player so that the MPRIS interface will no |
337 | + * longer have a current player to control |
338 | + */ |
339 | + void reset_current_player(); |
340 | void pause_other_sessions(Player::PlayerKey key); |
341 | |
342 | void run(); |
Looks good, but maybe we need to call update_ current_ player( ) also when adding complete track lists? Which is done with AddTrack(s) DBus calls.