Merge lp:~phablet-team/media-hub/fix-1538703 into lp:media-hub

Proposed by Konrad Zapałowicz
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
Reviewer Review Type Date Requested Status
Alfonso Sanchez-Beato Needs Fixing
Review via email: mp+291609@code.launchpad.net

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.

To post a comment you must log in.
Revision history for this message
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote : Posted in a previous version of this proposal

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.

review: Needs Information
Revision history for this message
Jim Hodapp (jhodapp) wrote : Posted in a previous version of this proposal

> 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.

Can you explain more why you think we need to do this? I don't see any gap that this would fix.

Revision history for this message
Jim Hodapp (jhodapp) wrote : Posted in a previous version of this proposal

Addressed review comments.

Revision history for this message
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote : Posted in a previous version of this proposal

LGTM

review: Approve
Revision history for this message
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote :

So I have just seen that Jim modified service.h too to add reset_current_player(), for some reason I did not notice last time I reviewed. TBH I do not like adding reset_current_player() and get_current_player() to service.h. That file is, in the end, defining a DBus interface so we should add only functions that make sense to a media-hub client, and these functions are not even implemented in the service stub (client library).

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 ServiceImplementation.

@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.

review: Needs Fixing
Revision history for this message
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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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();

Subscribers

People subscribed via source and target branches

to all changes: