Merge lp:~ricmm/media-hub/session-reattach-nonfixed into lp:media-hub
- session-reattach-nonfixed
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Jim Hodapp |
Approved revision: | 155 |
Merged at revision: | 133 |
Proposed branch: | lp:~ricmm/media-hub/session-reattach-nonfixed |
Merge into: | lp:media-hub |
Prerequisite: | lp:~phablet-team/media-hub/tracklist-cli |
Diff against target: |
1135 lines (+555/-61) 19 files modified
CMakeLists.txt (+1/-1) debian/changelog (+6/-0) include/core/media/player.h (+4/-0) include/core/media/service.h (+16/-0) src/core/media/mpris/service.h (+39/-0) src/core/media/player_configuration.h (+1/-1) src/core/media/player_implementation.cpp (+47/-17) src/core/media/player_implementation.h (+4/-0) src/core/media/player_stub.cpp (+22/-3) src/core/media/player_stub.h (+6/-1) src/core/media/server/server.cpp (+1/-1) src/core/media/service_implementation.cpp (+16/-0) src/core/media/service_implementation.h (+3/-0) src/core/media/service_skeleton.cpp (+235/-12) src/core/media/service_skeleton.h (+6/-0) src/core/media/service_stub.cpp (+39/-3) src/core/media/service_stub.h (+3/-0) tests/test-track-list/test_track_list.cpp (+99/-20) tests/test-track-list/test_track_list.h (+7/-2) |
To merge this branch: | bzr merge lp:~ricmm/media-hub/session-reattach-nonfixed |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Approve | |
Thomas Voß (community) | Approve | ||
Jim Hodapp (community) | code | Approve | |
Review via email: mp+256101@code.launchpad.net |
This proposal supersedes a proposal from 2015-04-10.
Commit message
Player session attaching/detaching with UUID
Description of the change
Player session attaching/detaching with UUID
PS Jenkins bot (ps-jenkins) wrote : | # |
Jim Hodapp (jhodapp) wrote : | # |
Looks good, a few things to fix.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:139
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Jim Hodapp (jhodapp) wrote : | # |
Looks good, thanks.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:140
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 141. By Ricardo Mendoza
-
Merge parent
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:141
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Thomas Voß (thomas-voss) wrote : | # |
A few comments inline, one bigger question:
What is the difference between reattach/detach and the existing resume_session functionality?
Jim Hodapp (jhodapp) wrote : | # |
Some added comments to my review and tvoss' review.
Thomas Voß (thomas-voss) wrote : | # |
Replied inline.
Jim Hodapp (jhodapp) : | # |
- 142. By Ricardo Mendoza
-
Address review comments and plug through no-impl methods of the Service parts
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:142
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 143. By Ricardo Mendoza
-
Not a reference
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:143
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 144. By Ricardo Mendoza
-
Correctly propagate track list changes from bus to local and viceversa
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:144
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Thomas Voß (thomas-voss) wrote : | # |
On Thu, Apr 16, 2015 at 5:14 PM, Jim Hodapp <email address hidden> wrote:
>
>
> Diff comments:
>
>> === modified file 'CMakeLists.txt'
>> --- CMakeLists.txt 2015-01-23 13:00:36 +0000
>> +++ CMakeLists.txt 2015-04-15 18:29:47 +0000
>> @@ -3,7 +3,7 @@
>> project(
>>
>> set(UBUNTU_
>> -set(UBUNTU_
>> +set(UBUNTU_
>> set(UBUNTU_
>>
>> set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -fPIC -pthread")
>>
>> === modified file 'debian/changelog'
>> --- debian/changelog 2015-04-02 16:43:42 +0000
>> +++ debian/changelog 2015-04-15 18:29:47 +0000
>> @@ -1,3 +1,9 @@
>> +media-hub (3.1.0) UNRELEASED; urgency=medium
>> +
>> + * Support for signalling player reconnection up the stack.
>> +
>> + -- Ricardo Mendoza <email address hidden> Fri, 10 Apr 2015 18:20:32 +0200
>> +
>> media-hub (3.0.0+
>>
>> [ Jim Hodapp ]
>>
>> === modified file 'include/
>> --- include/
>> +++ include/
>> @@ -126,6 +126,9 @@
>> Player& operator=(const Player&) = delete;
>> bool operator==(const Player&) const = delete;
>>
>> + virtual std::string uuid() const = 0;
>
> Yeah I would say this isn't hugely important though as the likely-hood of this happening is very slim. Also, we could just change it if that unlikely event occurred.
>
That's somewhat difficult as this is public facing API. Your call.
>> + virtual void reconnect() = 0;
>> +
>> virtual std::shared_
>> virtual PlayerKey key() const = 0;
>>
>>
>> === modified file 'include/
>> --- include/
>> +++ include/
>> @@ -42,9 +42,25 @@
>> Service& operator=(const Service&) = delete;
>> bool operator==(const Service&) const = delete;
>>
>> + /** @brief Creates a session with the media-hub service. */
>> virtual std::shared_
>> +
>> + /** @brief Detaches a UUID-identified session for later resuming. */
>> + virtual void detach_
>> +
>> + /** @brief Reattaches to a UUID-identified session that is in detached state. */
>> + virtual std::shared_
>> +
>> + /** @brief Asks the service to destroy a session. The session is destroyed when the client exits. */
>> + virtual void destroy_
>> +
>> + /** @brief Creates a fixed-named session with the media-hub service. */
>> virtual std::shared_
>> +
>> + /** @brief Resumes a fixed-name session directly by player key. */
>> virtual std::shared_
- 145. By Ricardo Mendoza
-
Remove printfs
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:145
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 146. By Ricardo Mendoza
-
Revert last changes
- 147. By Ricardo Mendoza
-
Delete player instance instead of abandoning
- 148. By Ricardo Mendoza
-
Update tracklist cli for new api
- 149. By Ricardo Mendoza
-
Merge parent
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:149
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 150. By Ricardo Mendoza
-
Implement full player destruction
- 151. By Ricardo Mendoza
-
Merge parent
- 152. By Ricardo Mendoza
-
Syntax error
- 153. By Ricardo Mendoza
-
Sync test cli
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:152
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:153
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 154. By Ricardo Mendoza
-
Merge parent
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:154
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 155. By Ricardo Mendoza
-
Merge parent
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:155
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2015-01-23 13:00:36 +0000 |
3 | +++ CMakeLists.txt 2015-04-20 15:56:34 +0000 |
4 | @@ -3,7 +3,7 @@ |
5 | project(ubuntu-media-hub) |
6 | |
7 | set(UBUNTU_MEDIA_HUB_VERSION_MAJOR 3) |
8 | -set(UBUNTU_MEDIA_HUB_VERSION_MINOR 0) |
9 | +set(UBUNTU_MEDIA_HUB_VERSION_MINOR 1) |
10 | set(UBUNTU_MEDIA_HUB_VERSION_PATCH 0) |
11 | |
12 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -fPIC -pthread") |
13 | |
14 | === modified file 'debian/changelog' |
15 | --- debian/changelog 2015-04-02 16:43:42 +0000 |
16 | +++ debian/changelog 2015-04-20 15:56:34 +0000 |
17 | @@ -1,3 +1,9 @@ |
18 | +media-hub (3.1.0) UNRELEASED; urgency=medium |
19 | + |
20 | + * Support for signalling player reconnection up the stack. |
21 | + |
22 | + -- Ricardo Mendoza <ricardo.mendoza@canonical.com> Fri, 10 Apr 2015 18:20:32 +0200 |
23 | + |
24 | media-hub (3.0.0+15.04.20150402-0ubuntu1) vivid; urgency=medium |
25 | |
26 | [ Jim Hodapp ] |
27 | |
28 | === modified file 'include/core/media/player.h' |
29 | --- include/core/media/player.h 2015-04-20 15:56:34 +0000 |
30 | +++ include/core/media/player.h 2015-04-20 15:56:34 +0000 |
31 | @@ -126,6 +126,10 @@ |
32 | Player& operator=(const Player&) = delete; |
33 | bool operator==(const Player&) const = delete; |
34 | |
35 | + virtual std::string uuid() const = 0; |
36 | + virtual void reconnect() = 0; |
37 | + virtual void abandon() = 0; |
38 | + |
39 | virtual std::shared_ptr<TrackList> track_list() = 0; |
40 | virtual PlayerKey key() const = 0; |
41 | |
42 | |
43 | === modified file 'include/core/media/service.h' |
44 | --- include/core/media/service.h 2014-09-30 06:51:15 +0000 |
45 | +++ include/core/media/service.h 2015-04-20 15:56:34 +0000 |
46 | @@ -42,9 +42,25 @@ |
47 | Service& operator=(const Service&) = delete; |
48 | bool operator==(const Service&) const = delete; |
49 | |
50 | + /** @brief Creates a session with the media-hub service. */ |
51 | virtual std::shared_ptr<Player> create_session(const Player::Configuration&) = 0; |
52 | + |
53 | + /** @brief Detaches a UUID-identified session for later resuming. */ |
54 | + virtual void detach_session(const std::string& uuid, const Player::Configuration&) = 0; |
55 | + |
56 | + /** @brief Reattaches to a UUID-identified session that is in detached state. */ |
57 | + virtual std::shared_ptr<Player> reattach_session(const std::string& uuid, const Player::Configuration&) = 0; |
58 | + |
59 | + /** @brief Asks the service to destroy a session. The session is destroyed when the client exits. */ |
60 | + virtual void destroy_session(const std::string& uuid, const Player::Configuration&) = 0; |
61 | + |
62 | + /** @brief Creates a fixed-named session with the media-hub service. */ |
63 | virtual std::shared_ptr<Player> create_fixed_session(const std::string& name, const Player::Configuration&) = 0; |
64 | + |
65 | + /** @brief Resumes a fixed-name session directly by player key. */ |
66 | virtual std::shared_ptr<Player> resume_session(Player::PlayerKey) = 0; |
67 | + |
68 | + /** @brief Pauses sessions other than the supplied one. */ |
69 | virtual void pause_other_sessions(Player::PlayerKey) = 0; |
70 | |
71 | protected: |
72 | |
73 | === modified file 'src/core/media/mpris/service.h' |
74 | --- src/core/media/mpris/service.h 2014-09-30 06:51:15 +0000 |
75 | +++ src/core/media/mpris/service.h 2015-04-20 15:56:34 +0000 |
76 | @@ -48,6 +48,42 @@ |
77 | } |
78 | }; |
79 | |
80 | + struct DetachingSession |
81 | + { |
82 | + static const std::string& name() |
83 | + { |
84 | + static const std::string s |
85 | + { |
86 | + "core.ubuntu.media.Service.Error.DetachingSession" |
87 | + }; |
88 | + return s; |
89 | + } |
90 | + }; |
91 | + |
92 | + struct ReattachingSession |
93 | + { |
94 | + static const std::string& name() |
95 | + { |
96 | + static const std::string s |
97 | + { |
98 | + "core.ubuntu.media.Service.Error.ReattachingSession" |
99 | + }; |
100 | + return s; |
101 | + } |
102 | + }; |
103 | + |
104 | + struct DestroyingSession |
105 | + { |
106 | + static const std::string& name() |
107 | + { |
108 | + static const std::string s |
109 | + { |
110 | + "core.ubuntu.media.Service.Error.DestroyingSession" |
111 | + }; |
112 | + return s; |
113 | + } |
114 | + }; |
115 | + |
116 | struct CreatingFixedSession |
117 | { |
118 | static const std::string& name() |
119 | @@ -74,6 +110,9 @@ |
120 | }; |
121 | |
122 | DBUS_CPP_METHOD_WITH_TIMEOUT_DEF(CreateSession, Service, 1000) |
123 | + DBUS_CPP_METHOD_WITH_TIMEOUT_DEF(DetachSession, Service, 1000) |
124 | + DBUS_CPP_METHOD_WITH_TIMEOUT_DEF(ReattachSession, Service, 1000) |
125 | + DBUS_CPP_METHOD_WITH_TIMEOUT_DEF(DestroySession, Service, 1000) |
126 | DBUS_CPP_METHOD_WITH_TIMEOUT_DEF(CreateFixedSession, Service, 1000) |
127 | DBUS_CPP_METHOD_WITH_TIMEOUT_DEF(ResumeSession, Service, 1000) |
128 | DBUS_CPP_METHOD_WITH_TIMEOUT_DEF(PauseOtherSessions, Service, 1000) |
129 | |
130 | === modified file 'src/core/media/player_configuration.h' |
131 | --- src/core/media/player_configuration.h 2015-04-20 15:56:34 +0000 |
132 | +++ src/core/media/player_configuration.h 2015-04-20 15:56:34 +0000 |
133 | @@ -27,7 +27,7 @@ |
134 | // to the implementation in a way that is opaque to the client. |
135 | struct core::ubuntu::media::Player::Configuration |
136 | { |
137 | - // Unique key for identifying the session. |
138 | + // Unique key for identifying the session path. |
139 | core::ubuntu::media::Player::PlayerKey key; |
140 | // The bus connection to expose objects on. |
141 | std::shared_ptr<core::dbus::Bus> bus; |
142 | |
143 | === modified file 'src/core/media/player_implementation.cpp' |
144 | --- src/core/media/player_implementation.cpp 2015-04-20 15:56:34 +0000 |
145 | +++ src/core/media/player_implementation.cpp 2015-04-20 15:56:34 +0000 |
146 | @@ -68,7 +68,7 @@ |
147 | previous_state(Engine::State::stopped), |
148 | engine_state_change_connection(engine->state().changed().connect(make_state_change_handler())), |
149 | engine_playback_status_change_connection(engine->playback_status_changed_signal().connect(make_playback_status_change_handler())), |
150 | - doing_go_to_track(false) |
151 | + doing_abandon(false) |
152 | { |
153 | // Poor man's logging of release/acquire events. |
154 | display_state_lock->acquired().connect([](media::power::DisplayState state) |
155 | @@ -301,7 +301,8 @@ |
156 | core::Connection engine_state_change_connection; |
157 | core::Connection engine_playback_status_change_connection; |
158 | // Prevent the TrackList from auto advancing to the next track |
159 | - std::atomic<bool> doing_go_to_track; |
160 | + std::mutex doing_go_to_track; |
161 | + std::atomic<bool> doing_abandon; |
162 | }; |
163 | |
164 | template<typename Parent> |
165 | @@ -390,23 +391,26 @@ |
166 | |
167 | d->engine->about_to_finish_signal().connect([this]() |
168 | { |
169 | + if (d->doing_abandon) |
170 | + return; |
171 | + |
172 | Parent::about_to_finish()(); |
173 | |
174 | - if (!d->doing_go_to_track) |
175 | + // This lambda needs to be mutually exclusive with the on_go_to_track lambda below |
176 | + d->doing_go_to_track.lock(); |
177 | + |
178 | + const media::Track::Id prev_track_id = d->track_list->current(); |
179 | + // Make sure that the TrackList keeps advancing. The logic for what gets played next, |
180 | + // if anything at all, occurs in TrackListSkeleton::next() |
181 | + const Track::UriType uri = d->track_list->query_uri_for_track(d->track_list->next()); |
182 | + if (prev_track_id != d->track_list->current() && !uri.empty()) |
183 | { |
184 | - const media::Track::Id prev_track_id = d->track_list->current(); |
185 | - // Make sure that the TrackList keeps advancing. The logic for what gets played next, |
186 | - // if anything at all, occurs in TrackListSkeleton::next() |
187 | - const Track::UriType uri = d->track_list->query_uri_for_track(d->track_list->next()); |
188 | - if (prev_track_id != d->track_list->current() && !uri.empty()) |
189 | - { |
190 | - std::cout << "Setting next track on playbin: " << uri << std::endl; |
191 | - static const bool do_pipeline_reset = false; |
192 | - d->engine->open_resource_for_uri(uri, do_pipeline_reset); |
193 | - } |
194 | + std::cout << "Setting next track on playbin: " << uri << std::endl; |
195 | + static const bool do_pipeline_reset = false; |
196 | + d->engine->open_resource_for_uri(uri, do_pipeline_reset); |
197 | } |
198 | - else |
199 | - std::cout << "Not auto-advancing the TrackList since doing_go_to_track is true" << std::endl; |
200 | + |
201 | + d->doing_go_to_track.unlock(); |
202 | }); |
203 | |
204 | d->engine->client_disconnected_signal().connect([this]() |
205 | @@ -443,7 +447,8 @@ |
206 | { |
207 | // This prevents the TrackList from auto advancing in other areas such as the about_to_finish signal |
208 | // handler. |
209 | - d->doing_go_to_track = true; |
210 | + // This lambda needs to be mutually exclusive with the about_to_finish lambda above |
211 | + d->doing_go_to_track.lock(); |
212 | |
213 | const media::Track::Id id = p.first; |
214 | const bool toggle_player_state = p.second; |
215 | @@ -463,7 +468,8 @@ |
216 | if (toggle_player_state) |
217 | d->engine->play(); |
218 | |
219 | - d->doing_go_to_track = false; |
220 | + d->doing_go_to_track.unlock(); |
221 | + |
222 | }); |
223 | |
224 | // Everything is setup, we now subscribe to death notifications. |
225 | @@ -474,6 +480,9 @@ |
226 | { |
227 | if (auto sp = wp.lock()) |
228 | { |
229 | + if (sp->doing_abandon) |
230 | + return; |
231 | + |
232 | if (died != sp->config.key) |
233 | return; |
234 | |
235 | @@ -519,6 +528,27 @@ |
236 | } |
237 | |
238 | template<typename Parent> |
239 | +std::string media::PlayerImplementation<Parent>::uuid() const |
240 | +{ |
241 | + // No impl for now, as not needed internally. |
242 | + return std::string{}; |
243 | +} |
244 | + |
245 | +template<typename Parent> |
246 | +void media::PlayerImplementation<Parent>::reconnect() |
247 | +{ |
248 | + d->config.client_death_observer->register_for_death_notifications_with_key(d->config.key); |
249 | +} |
250 | + |
251 | +template<typename Parent> |
252 | +void media::PlayerImplementation<Parent>::abandon() |
253 | +{ |
254 | + // Signal client disconnection due to abandonment of player |
255 | + d->doing_abandon = true; |
256 | + d->on_client_died(); |
257 | +} |
258 | + |
259 | +template<typename Parent> |
260 | std::shared_ptr<media::TrackList> media::PlayerImplementation<Parent>::track_list() |
261 | { |
262 | return d->track_list; |
263 | |
264 | === modified file 'src/core/media/player_implementation.h' |
265 | --- src/core/media/player_implementation.h 2015-04-20 15:56:34 +0000 |
266 | +++ src/core/media/player_implementation.h 2015-04-20 15:56:34 +0000 |
267 | @@ -55,6 +55,10 @@ |
268 | PlayerImplementation(const Configuration& configuration); |
269 | ~PlayerImplementation(); |
270 | |
271 | + virtual std::string uuid() const; |
272 | + virtual void reconnect(); |
273 | + virtual void abandon(); |
274 | + |
275 | virtual std::shared_ptr<TrackList> track_list(); |
276 | virtual Player::PlayerKey key() const; |
277 | |
278 | |
279 | === modified file 'src/core/media/player_stub.cpp' |
280 | --- src/core/media/player_stub.cpp 2015-04-20 15:56:34 +0000 |
281 | +++ src/core/media/player_stub.cpp 2015-04-20 15:56:34 +0000 |
282 | @@ -44,11 +44,13 @@ |
283 | { |
284 | Private(const std::shared_ptr<Service>& parent, |
285 | const std::shared_ptr<core::dbus::Service>& service, |
286 | - const std::shared_ptr<core::dbus::Object>& object |
287 | + const std::shared_ptr<core::dbus::Object>& object, |
288 | + const std::string& uuid |
289 | ) : parent(parent), |
290 | service(service), |
291 | object(object), |
292 | key(object->invoke_method_synchronously<mpris::Player::Key, media::Player::PlayerKey>().value()), |
293 | + uuid(uuid), |
294 | sink_factory(media::video::make_platform_default_sink_factory(key)), |
295 | properties |
296 | { |
297 | @@ -96,6 +98,7 @@ |
298 | dbus::Service::Ptr service; |
299 | dbus::Object::Ptr object; |
300 | media::Player::PlayerKey key; |
301 | + std::string uuid; |
302 | media::video::SinkFactory sink_factory; |
303 | struct |
304 | { |
305 | @@ -213,8 +216,9 @@ |
306 | media::PlayerStub::PlayerStub( |
307 | const std::shared_ptr<Service>& parent, |
308 | const std::shared_ptr<core::dbus::Service>& service, |
309 | - const std::shared_ptr<core::dbus::Object>& object) |
310 | - : d(new Private{parent, service, object}) |
311 | + const std::shared_ptr<core::dbus::Object>& object, |
312 | + const std::string& uuid) |
313 | + : d(new Private{parent, service, object, uuid}) |
314 | { |
315 | } |
316 | |
317 | @@ -222,6 +226,21 @@ |
318 | { |
319 | } |
320 | |
321 | +std::string media::PlayerStub::uuid() const |
322 | +{ |
323 | + return d->uuid; |
324 | +} |
325 | + |
326 | +void media::PlayerStub::reconnect() |
327 | +{ |
328 | + // No implementation |
329 | +} |
330 | + |
331 | +void media::PlayerStub::abandon() |
332 | +{ |
333 | + // No implementation |
334 | +} |
335 | + |
336 | std::shared_ptr<media::TrackList> media::PlayerStub::track_list() |
337 | { |
338 | if (!d->track_list) |
339 | |
340 | === modified file 'src/core/media/player_stub.h' |
341 | --- src/core/media/player_stub.h 2015-04-20 15:56:34 +0000 |
342 | +++ src/core/media/player_stub.h 2015-04-20 15:56:34 +0000 |
343 | @@ -40,10 +40,15 @@ |
344 | explicit PlayerStub( |
345 | const std::shared_ptr<Service>& parent, |
346 | const std::shared_ptr<core::dbus::Service>& service, |
347 | - const std::shared_ptr<core::dbus::Object>& object); |
348 | + const std::shared_ptr<core::dbus::Object>& object, |
349 | + const std::string& uuid = std::string{}); |
350 | |
351 | ~PlayerStub(); |
352 | |
353 | + virtual std::string uuid() const; |
354 | + virtual void reconnect(); |
355 | + virtual void abandon(); |
356 | + |
357 | virtual std::shared_ptr<TrackList> track_list(); |
358 | virtual PlayerKey key() const; |
359 | |
360 | |
361 | === modified file 'src/core/media/server/server.cpp' |
362 | --- src/core/media/server/server.cpp 2014-12-15 14:43:44 +0000 |
363 | +++ src/core/media/server/server.cpp 2015-04-20 15:56:34 +0000 |
364 | @@ -123,7 +123,7 @@ |
365 | { |
366 | impl, |
367 | player_store, |
368 | - |
369 | + external_services |
370 | }); |
371 | |
372 | std::thread service_worker |
373 | |
374 | === modified file 'src/core/media/service_implementation.cpp' |
375 | --- src/core/media/service_implementation.cpp 2015-04-20 15:56:34 +0000 |
376 | +++ src/core/media/service_implementation.cpp 2015-04-20 15:56:34 +0000 |
377 | @@ -218,6 +218,22 @@ |
378 | return player; |
379 | } |
380 | |
381 | +void media::ServiceImplementation::detach_session(const std::string&, const media::Player::Configuration&) |
382 | +{ |
383 | + // no impl |
384 | +} |
385 | + |
386 | +std::shared_ptr<media::Player> media::ServiceImplementation::reattach_session(const std::string&, const media::Player::Configuration&) |
387 | +{ |
388 | + // no impl |
389 | + return std::shared_ptr<media::Player>(); |
390 | +} |
391 | + |
392 | +void media::ServiceImplementation::destroy_session(const std::string&, const media::Player::Configuration&) |
393 | +{ |
394 | + // no impl |
395 | +} |
396 | + |
397 | std::shared_ptr<media::Player> media::ServiceImplementation::create_fixed_session(const std::string&, const media::Player::Configuration&) |
398 | { |
399 | // no impl |
400 | |
401 | === modified file 'src/core/media/service_implementation.h' |
402 | --- src/core/media/service_implementation.h 2015-04-02 14:46:52 +0000 |
403 | +++ src/core/media/service_implementation.h 2015-04-20 15:56:34 +0000 |
404 | @@ -44,6 +44,9 @@ |
405 | ~ServiceImplementation (); |
406 | |
407 | std::shared_ptr<Player> create_session(const Player::Configuration&); |
408 | + void detach_session(const std::string&, const Player::Configuration&); |
409 | + std::shared_ptr<Player> reattach_session(const std::string&, const Player::Configuration&); |
410 | + void destroy_session(const std::string&, const Player::Configuration&); |
411 | std::shared_ptr<Player> create_fixed_session(const std::string& name, const Player::Configuration&); |
412 | std::shared_ptr<Player> resume_session(Player::PlayerKey key); |
413 | void pause_other_sessions(Player::PlayerKey key); |
414 | |
415 | === modified file 'src/core/media/service_skeleton.cpp' |
416 | --- src/core/media/service_skeleton.cpp 2015-04-20 15:56:34 +0000 |
417 | +++ src/core/media/service_skeleton.cpp 2015-04-20 15:56:34 +0000 |
418 | @@ -35,6 +35,10 @@ |
419 | |
420 | #include <core/posix/this_process.h> |
421 | |
422 | +#include <boost/uuid/uuid.hpp> |
423 | +#include <boost/uuid/uuid_generators.hpp> |
424 | +#include <boost/uuid/uuid_io.hpp> |
425 | + |
426 | #include <map> |
427 | #include <regex> |
428 | #include <sstream> |
429 | @@ -50,17 +54,33 @@ |
430 | struct media::ServiceSkeleton::Private |
431 | { |
432 | Private(media::ServiceSkeleton* impl, const ServiceSkeleton::Configuration& config) |
433 | - : impl(impl), |
434 | + : request_context_resolver(media::apparmor::ubuntu::make_platform_default_request_context_resolver(config.external_services)), |
435 | + impl(impl), |
436 | object(impl->access_service()->add_object_for_path( |
437 | dbus::traits::Service<media::Service>::object_path())), |
438 | - exported(impl->access_bus(), config.cover_art_resolver), |
439 | - configuration(config) |
440 | + configuration(config), |
441 | + exported(impl->access_bus(), config.cover_art_resolver) |
442 | { |
443 | object->install_method_handler<mpris::Service::CreateSession>( |
444 | std::bind( |
445 | &Private::handle_create_session, |
446 | this, |
447 | std::placeholders::_1)); |
448 | + object->install_method_handler<mpris::Service::DetachSession>( |
449 | + std::bind( |
450 | + &Private::handle_detach_session, |
451 | + this, |
452 | + std::placeholders::_1)); |
453 | + object->install_method_handler<mpris::Service::ReattachSession>( |
454 | + std::bind( |
455 | + &Private::handle_reattach_session, |
456 | + this, |
457 | + std::placeholders::_1)); |
458 | + object->install_method_handler<mpris::Service::DestroySession>( |
459 | + std::bind( |
460 | + &Private::handle_destroy_session, |
461 | + this, |
462 | + std::placeholders::_1)); |
463 | object->install_method_handler<mpris::Service::CreateFixedSession>( |
464 | std::bind( |
465 | &Private::handle_create_fixed_session, |
466 | @@ -78,24 +98,26 @@ |
467 | std::placeholders::_1)); |
468 | } |
469 | |
470 | - std::pair<std::string, media::Player::PlayerKey> create_session_info() |
471 | + std::tuple<std::string, media::Player::PlayerKey, std::string> create_session_info() |
472 | { |
473 | static unsigned int session_counter = 0; |
474 | |
475 | unsigned int current_session = session_counter++; |
476 | + boost::uuids::uuid uuid = gen(); |
477 | |
478 | std::stringstream ss; |
479 | ss << "/core/ubuntu/media/Service/sessions/" << current_session; |
480 | |
481 | - return std::make_pair(ss.str(), media::Player::PlayerKey(current_session)); |
482 | + return std::make_tuple(ss.str(), media::Player::PlayerKey(current_session), to_string(uuid)); |
483 | } |
484 | |
485 | void handle_create_session(const core::dbus::Message::Ptr& msg) |
486 | { |
487 | - auto session_info = create_session_info(); |
488 | + auto session_info = create_session_info(); |
489 | |
490 | - dbus::types::ObjectPath op{session_info.first}; |
491 | - media::Player::PlayerKey key{session_info.second}; |
492 | + dbus::types::ObjectPath op{std::get<0>(session_info)}; |
493 | + media::Player::PlayerKey key{std::get<1>(session_info)}; |
494 | + std::string uuid{std::get<2>(session_info)}; |
495 | |
496 | media::Player::Configuration config |
497 | { |
498 | @@ -105,11 +127,21 @@ |
499 | impl->access_service()->add_object_for_path(op) |
500 | }; |
501 | |
502 | + std::cout << "Session created by request of: " << msg->sender() << ", uuid: " << uuid << ", path:" << op << std::endl; |
503 | + |
504 | try |
505 | { |
506 | configuration.player_store->add_player_for_key(key, impl->create_session(config)); |
507 | + uuid_player_map.insert(std::make_pair(uuid, key)); |
508 | + |
509 | + request_context_resolver->resolve_context_for_dbus_name_async(msg->sender(), [this, key, msg](const media::apparmor::ubuntu::Context& context) |
510 | + { |
511 | + fprintf(stderr, "%s():%d -- app_name='%s', attached\n", __func__, __LINE__, context.str().c_str()); |
512 | + player_owner_map.insert(std::make_pair(key, std::make_tuple(context.str(), true, msg->sender()))); |
513 | + }); |
514 | + |
515 | auto reply = dbus::Message::make_method_return(msg); |
516 | - reply->writer() << op; |
517 | + reply->writer() << std::make_tuple(op, uuid); |
518 | |
519 | impl->access_bus()->send(reply); |
520 | } catch(const std::runtime_error& e) |
521 | @@ -122,6 +154,174 @@ |
522 | } |
523 | } |
524 | |
525 | + void handle_detach_session(const core::dbus::Message::Ptr& msg) |
526 | + { |
527 | + try |
528 | + { |
529 | + std::string uuid; |
530 | + msg->reader() >> uuid; |
531 | + |
532 | + auto key = uuid_player_map.at(uuid); |
533 | + |
534 | + if (player_owner_map.count(key) != 0) { |
535 | + auto info = player_owner_map.at(key); |
536 | + // Check if session is attached(1) and that the detachment |
537 | + // request comes from the same peer(2) that created the session. |
538 | + if (std::get<1>(info) && (std::get<2>(info) == msg->sender())) { // Player is attached |
539 | + std::get<1>(info) = false; // Detached |
540 | + std::get<2>(info).clear(); // Clear registered sender/peer |
541 | + auto player = configuration.player_store->player_for_key(key); |
542 | + player->lifetime().set(media::Player::Lifetime::resumable); |
543 | + } |
544 | + } |
545 | + |
546 | + auto reply = dbus::Message::make_method_return(msg); |
547 | + impl->access_bus()->send(reply); |
548 | + |
549 | + } catch(const std::runtime_error& e) |
550 | + { |
551 | + auto reply = dbus::Message::make_error( |
552 | + msg, |
553 | + mpris::Service::Errors::DetachingSession::name(), |
554 | + e.what()); |
555 | + impl->access_bus()->send(reply); |
556 | + } |
557 | + } |
558 | + |
559 | + void handle_reattach_session(const core::dbus::Message::Ptr& msg) |
560 | + { |
561 | + try |
562 | + { |
563 | + std::string uuid; |
564 | + msg->reader() >> uuid; |
565 | + |
566 | + if (uuid_player_map.count(uuid) != 0) { |
567 | + auto key = uuid_player_map.at(uuid); |
568 | + if (not configuration.player_store->has_player_for_key(key)) { |
569 | + auto reply = dbus::Message::make_error( |
570 | + msg, |
571 | + mpris::Service::Errors::ReattachingSession::name(), |
572 | + "Unable to locate player session"); |
573 | + impl->access_bus()->send(reply); |
574 | + return; |
575 | + } |
576 | + std::stringstream ss; |
577 | + ss << "/core/ubuntu/media/Service/sessions/" << key; |
578 | + dbus::types::ObjectPath op{ss.str()}; |
579 | + |
580 | + request_context_resolver->resolve_context_for_dbus_name_async(msg->sender(), [this, msg, key, op](const media::apparmor::ubuntu::Context& context) |
581 | + { |
582 | + auto info = player_owner_map.at(key); |
583 | + fprintf(stderr, "%s():%d -- reattach app_name='%s', info='%s', '%s'\n", __func__, __LINE__, context.str().c_str(), std::get<0>(info).c_str(), std::get<2>(info).c_str()); |
584 | + if (std::get<0>(info) == context.str()) { |
585 | + std::get<1>(info) = true; // Set to Attached |
586 | + std::get<2>(info) = msg->sender(); // Register new owner |
587 | + |
588 | + // Signal player reconnection |
589 | + auto player = configuration.player_store->player_for_key(key); |
590 | + player->reconnect(); |
591 | + |
592 | + auto reply = dbus::Message::make_method_return(msg); |
593 | + reply->writer() << op; |
594 | + |
595 | + impl->access_bus()->send(reply); |
596 | + } |
597 | + else { |
598 | + auto reply = dbus::Message::make_error( |
599 | + msg, |
600 | + mpris::Service::Errors::ReattachingSession::name(), |
601 | + "Invalid permissions for the requested session"); |
602 | + impl->access_bus()->send(reply); |
603 | + return; |
604 | + } |
605 | + }); |
606 | + } |
607 | + else { |
608 | + auto reply = dbus::Message::make_error( |
609 | + msg, |
610 | + mpris::Service::Errors::ReattachingSession::name(), |
611 | + "Invalid session"); |
612 | + impl->access_bus()->send(reply); |
613 | + return; |
614 | + } |
615 | + } catch(const std::runtime_error& e) |
616 | + { |
617 | + auto reply = dbus::Message::make_error( |
618 | + msg, |
619 | + mpris::Service::Errors::ReattachingSession::name(), |
620 | + e.what()); |
621 | + impl->access_bus()->send(reply); |
622 | + } |
623 | + } |
624 | + |
625 | + void handle_destroy_session(const core::dbus::Message::Ptr& msg) |
626 | + { |
627 | + |
628 | + try |
629 | + { |
630 | + std::string uuid; |
631 | + msg->reader() >> uuid; |
632 | + |
633 | + if (uuid_player_map.count(uuid) != 0) { |
634 | + auto key = uuid_player_map.at(uuid); |
635 | + if (not configuration.player_store->has_player_for_key(key)) { |
636 | + auto reply = dbus::Message::make_error( |
637 | + msg, |
638 | + mpris::Service::Errors::DestroyingSession::name(), |
639 | + "Unable to locate player session"); |
640 | + impl->access_bus()->send(reply); |
641 | + return; |
642 | + } |
643 | + |
644 | + // Remove control entries from the map, at this point |
645 | + // the session is no longer usable. |
646 | + uuid_player_map.erase(uuid); |
647 | + |
648 | + request_context_resolver->resolve_context_for_dbus_name_async(msg->sender(), [this, msg, key](const media::apparmor::ubuntu::Context& context) |
649 | + { |
650 | + auto info = player_owner_map.at(key); |
651 | + fprintf(stderr, "%s():%d -- Destroying app_name='%s', info='%s', '%s'\n", __func__, __LINE__, context.str().c_str(), std::get<0>(info).c_str(), std::get<2>(info).c_str()); |
652 | + if (std::get<0>(info) == context.str()) { |
653 | + player_owner_map.erase(key); |
654 | + |
655 | + // Reset lifecycle to non-resumable on the now-abandoned session |
656 | + auto player = configuration.player_store->player_for_key(key); |
657 | + |
658 | + // Delete player instance by abandonment |
659 | + player->lifetime().set(media::Player::Lifetime::normal); |
660 | + player->abandon(); |
661 | + |
662 | + auto reply = dbus::Message::make_method_return(msg); |
663 | + impl->access_bus()->send(reply); |
664 | + } |
665 | + else { |
666 | + auto reply = dbus::Message::make_error( |
667 | + msg, |
668 | + mpris::Service::Errors::DestroyingSession::name(), |
669 | + "Invalid permissions for the requested session"); |
670 | + impl->access_bus()->send(reply); |
671 | + return; |
672 | + } |
673 | + }); |
674 | + } |
675 | + else { |
676 | + auto reply = dbus::Message::make_error( |
677 | + msg, |
678 | + mpris::Service::Errors::DestroyingSession::name(), |
679 | + "Invalid session"); |
680 | + impl->access_bus()->send(reply); |
681 | + return; |
682 | + } |
683 | + } catch(const std::runtime_error& e) |
684 | + { |
685 | + auto reply = dbus::Message::make_error( |
686 | + msg, |
687 | + mpris::Service::Errors::DestroyingSession::name(), |
688 | + e.what()); |
689 | + impl->access_bus()->send(reply); |
690 | + } |
691 | + } |
692 | + |
693 | void handle_create_fixed_session(const core::dbus::Message::Ptr& msg) |
694 | { |
695 | try |
696 | @@ -133,8 +333,8 @@ |
697 | // Create new session |
698 | auto session_info = create_session_info(); |
699 | |
700 | - dbus::types::ObjectPath op{session_info.first}; |
701 | - media::Player::PlayerKey key{session_info.second}; |
702 | + dbus::types::ObjectPath op{std::get<0>(session_info)}; |
703 | + media::Player::PlayerKey key{std::get<1>(session_info)}; |
704 | |
705 | media::Player::Configuration config |
706 | { |
707 | @@ -149,7 +349,6 @@ |
708 | |
709 | configuration.player_store->add_player_for_key(key, session); |
710 | |
711 | - |
712 | named_player_map.insert(std::make_pair(name, key)); |
713 | |
714 | auto reply = dbus::Message::make_method_return(msg); |
715 | @@ -233,6 +432,7 @@ |
716 | impl->access_bus()->send(reply); |
717 | } |
718 | |
719 | + media::apparmor::ubuntu::RequestContextResolver::Ptr request_context_resolver; |
720 | media::ServiceSkeleton* impl; |
721 | dbus::Object::Ptr object; |
722 | |
723 | @@ -240,6 +440,14 @@ |
724 | ServiceSkeleton::Configuration configuration; |
725 | // We map named/fixed player instances to their respective keys. |
726 | std::map<std::string, media::Player::PlayerKey> named_player_map; |
727 | + // We map UUIDs to their respective keys. |
728 | + std::map<std::string, media::Player::PlayerKey> uuid_player_map; |
729 | + // We keep a list of keys and their respective owners and states. |
730 | + // value: (owner context, attached state, attached dbus name) |
731 | + std::map<media::Player::PlayerKey, std::tuple<std::string, bool, std::string>> player_owner_map; |
732 | + |
733 | + boost::uuids::random_generator gen; |
734 | + |
735 | // We expose the entire service as an MPRIS player. |
736 | struct Exported |
737 | { |
738 | @@ -527,6 +735,21 @@ |
739 | return d->configuration.impl->create_session(config); |
740 | } |
741 | |
742 | +void media::ServiceSkeleton::detach_session(const std::string& uuid, const media::Player::Configuration& config) |
743 | +{ |
744 | + return d->configuration.impl->detach_session(uuid, config); |
745 | +} |
746 | + |
747 | +std::shared_ptr<media::Player> media::ServiceSkeleton::reattach_session(const std::string& uuid, const media::Player::Configuration& config) |
748 | +{ |
749 | + return d->configuration.impl->reattach_session(uuid, config); |
750 | +} |
751 | + |
752 | +void media::ServiceSkeleton::destroy_session(const std::string& uuid, const media::Player::Configuration& config) |
753 | +{ |
754 | + return d->configuration.impl->destroy_session(uuid, config); |
755 | +} |
756 | + |
757 | std::shared_ptr<media::Player> media::ServiceSkeleton::create_fixed_session(const std::string& name, const media::Player::Configuration&config) |
758 | { |
759 | return d->configuration.impl->create_fixed_session(name, config); |
760 | |
761 | === modified file 'src/core/media/service_skeleton.h' |
762 | --- src/core/media/service_skeleton.h 2014-12-15 14:43:44 +0000 |
763 | +++ src/core/media/service_skeleton.h 2015-04-20 15:56:34 +0000 |
764 | @@ -19,6 +19,8 @@ |
765 | #ifndef CORE_UBUNTU_MEDIA_SERVICE_SKELETON_H_ |
766 | #define CORE_UBUNTU_MEDIA_SERVICE_SKELETON_H_ |
767 | |
768 | +#include "apparmor/ubuntu.h" |
769 | + |
770 | #include <core/media/service.h> |
771 | |
772 | #include "cover_art_resolver.h" |
773 | @@ -43,6 +45,7 @@ |
774 | { |
775 | std::shared_ptr<Service> impl; |
776 | KeyedPlayerStore::Ptr player_store; |
777 | + helper::ExternalServices& external_services; |
778 | CoverArtResolver cover_art_resolver; |
779 | }; |
780 | |
781 | @@ -51,6 +54,9 @@ |
782 | |
783 | // From media::Service |
784 | std::shared_ptr<Player> create_session(const Player::Configuration&); |
785 | + void detach_session(const std::string&, const Player::Configuration&); |
786 | + std::shared_ptr<Player> reattach_session(const std::string&, const Player::Configuration&); |
787 | + void destroy_session(const std::string&, const media::Player::Configuration&); |
788 | std::shared_ptr<Player> create_fixed_session(const std::string& name, const Player::Configuration&); |
789 | std::shared_ptr<Player> resume_session(Player::PlayerKey); |
790 | void pause_other_sessions(Player::PlayerKey key); |
791 | |
792 | === modified file 'src/core/media/service_stub.cpp' |
793 | --- src/core/media/service_stub.cpp 2015-04-20 15:56:34 +0000 |
794 | +++ src/core/media/service_stub.cpp 2015-04-20 15:56:34 +0000 |
795 | @@ -58,7 +58,7 @@ |
796 | std::shared_ptr<media::Player> media::ServiceStub::create_session(const media::Player::Configuration&) |
797 | { |
798 | auto op = d->object->invoke_method_synchronously<mpris::Service::CreateSession, |
799 | - dbus::types::ObjectPath>(); |
800 | + std::tuple<dbus::types::ObjectPath, std::string>>(); |
801 | |
802 | if (op.is_error()) |
803 | throw std::runtime_error("Problem creating session: " + op.error()); |
804 | @@ -67,8 +67,44 @@ |
805 | { |
806 | shared_from_this(), |
807 | access_service(), |
808 | - access_service()->object_for_path(op.value()) |
809 | - }); |
810 | + access_service()->object_for_path(std::get<0>(op.value())), |
811 | + std::get<1>(op.value()) |
812 | + }); |
813 | +} |
814 | + |
815 | +void media::ServiceStub::detach_session(const std::string& uuid, const media::Player::Configuration&) |
816 | +{ |
817 | + auto op = d->object->invoke_method_synchronously<mpris::Service::DetachSession, |
818 | + void>(uuid); |
819 | + |
820 | + if (op.is_error()) |
821 | + throw std::runtime_error("Problem detaching session: " + op.error()); |
822 | +} |
823 | + |
824 | +std::shared_ptr<media::Player> media::ServiceStub::reattach_session(const std::string& uuid, const media::Player::Configuration&) |
825 | +{ |
826 | + auto op = d->object->invoke_method_synchronously<mpris::Service::ReattachSession, |
827 | + dbus::types::ObjectPath>(uuid); |
828 | + |
829 | + if (op.is_error()) |
830 | + throw std::runtime_error("Problem reattaching session: " + op.error()); |
831 | + |
832 | + return std::shared_ptr<media::Player>(new media::PlayerStub |
833 | + { |
834 | + shared_from_this(), |
835 | + access_service(), |
836 | + access_service()->object_for_path(op.value()), |
837 | + uuid |
838 | + }); |
839 | +} |
840 | + |
841 | +void media::ServiceStub::destroy_session(const std::string& uuid, const media::Player::Configuration&) |
842 | +{ |
843 | + auto op = d->object->invoke_method_synchronously<mpris::Service::DestroySession, |
844 | + void>(uuid); |
845 | + |
846 | + if (op.is_error()) |
847 | + throw std::runtime_error("Problem destroying session: " + op.error()); |
848 | } |
849 | |
850 | std::shared_ptr<media::Player> media::ServiceStub::create_fixed_session(const std::string& name, const media::Player::Configuration&) |
851 | |
852 | === modified file 'src/core/media/service_stub.h' |
853 | --- src/core/media/service_stub.h 2014-10-23 14:42:59 +0000 |
854 | +++ src/core/media/service_stub.h 2015-04-20 15:56:34 +0000 |
855 | @@ -40,6 +40,9 @@ |
856 | ~ServiceStub(); |
857 | |
858 | std::shared_ptr<Player> create_session(const Player::Configuration&); |
859 | + void detach_session(const std::string& uuid, const Player::Configuration&); |
860 | + std::shared_ptr<Player> reattach_session(const std::string& uuid, const Player::Configuration&); |
861 | + void destroy_session(const std::string& uuid, const Player::Configuration&); |
862 | std::shared_ptr<Player> create_fixed_session(const std::string& name, const Player::Configuration&); |
863 | std::shared_ptr<Player> resume_session(Player::PlayerKey key); |
864 | void pause_other_sessions(Player::PlayerKey key); |
865 | |
866 | === modified file 'tests/test-track-list/test_track_list.cpp' |
867 | --- tests/test-track-list/test_track_list.cpp 2015-04-20 15:56:34 +0000 |
868 | +++ tests/test-track-list/test_track_list.cpp 2015-04-20 15:56:34 +0000 |
869 | @@ -44,7 +44,7 @@ |
870 | { |
871 | } |
872 | |
873 | -void media::TestTrackList::create_new_player_session() |
874 | +std::string media::TestTrackList::create_new_player_session() |
875 | { |
876 | try { |
877 | m_hubPlayerSession = m_hubService->create_session(media::Player::Client::default_configuration()); |
878 | @@ -59,12 +59,53 @@ |
879 | catch (std::runtime_error &e) { |
880 | cerr << "FATAL: Failed to retrieve the current player's TrackList: " << e.what() << endl; |
881 | } |
882 | -} |
883 | - |
884 | -void media::TestTrackList::destroy_player_session() |
885 | -{ |
886 | - // TODO: explicitly add a destroy session to the Service class after ricmm lands his new creation_session |
887 | - // that returns a session ID. This will allow me to clear the tracklist after each test. |
888 | + |
889 | + std::string uuid; |
890 | + try { |
891 | + uuid.assign(m_hubPlayerSession->uuid()); |
892 | + } |
893 | + catch (std::runtime_error &e) { |
894 | + cerr << "FATAL: Failed to retrieve the current player's uuid: " << e.what() << endl; |
895 | + } |
896 | + |
897 | + cout << "Connected to session " << uuid << endl; |
898 | + return uuid; |
899 | +} |
900 | + |
901 | +void media::TestTrackList::detach_player_session(const std::string &uuid) |
902 | +{ |
903 | + try { |
904 | + m_hubService->detach_session(uuid, media::Player::Client::default_configuration()); |
905 | + } |
906 | + catch (std::runtime_error &e) { |
907 | + cerr << "FATAL: Failed to detach the media-hub player session: " << e.what() << endl; |
908 | + } |
909 | + |
910 | + cout << "Detached session " << uuid << endl; |
911 | +} |
912 | + |
913 | +void media::TestTrackList::reattach_player_session(const std::string &uuid) |
914 | +{ |
915 | + try { |
916 | + m_hubPlayerSession = m_hubService->reattach_session(uuid, media::Player::Client::default_configuration()); |
917 | + } |
918 | + catch (std::runtime_error &e) { |
919 | + cerr << "FATAL: Failed to reattach the media-hub player session: " << e.what() << endl; |
920 | + } |
921 | + |
922 | + try { |
923 | + m_hubTrackList = m_hubPlayerSession->track_list(); |
924 | + } |
925 | + catch (std::runtime_error &e) { |
926 | + cerr << "FATAL: Failed to retrieve the current player's TrackList: " << e.what() << endl; |
927 | + } |
928 | + |
929 | + cout << "Re-connected to session " << uuid << endl; |
930 | +} |
931 | + |
932 | +void media::TestTrackList::destroy_player_session(const std::string &uuid) |
933 | +{ |
934 | + m_hubService->destroy_session(uuid, media::Player::Client::default_configuration()); |
935 | m_hubPlayerSession.reset(); |
936 | } |
937 | |
938 | @@ -92,13 +133,13 @@ |
939 | { |
940 | cout << "--> Running test: test_basic_playback" << std::endl; |
941 | |
942 | - core::Connection c =m_hubTrackList->on_track_added().connect([](const media::Track::Id &new_id) |
943 | + const std::string uuid = create_new_player_session(); |
944 | + |
945 | + core::Connection c = m_hubTrackList->on_track_added().connect([](const media::Track::Id &new_id) |
946 | { |
947 | cout << "Added track to TrackList with Id: " << new_id << endl; |
948 | }); |
949 | |
950 | - //create_new_player_session(); |
951 | - |
952 | m_hubPlayerSession->open_uri(uri1); |
953 | if (!uri2.empty()) |
954 | add_track(uri2); |
955 | @@ -118,13 +159,34 @@ |
956 | |
957 | c.disconnect(); |
958 | |
959 | - //destroy_player_session(); |
960 | + destroy_player_session(uuid); |
961 | +} |
962 | + |
963 | +void media::TestTrackList::test_tracklist_resume(const std::string &uri1, const std::string &uri2, const std::string &uuid) |
964 | +{ |
965 | + cout << "--> Running test: test_tracklist_resume" << std::endl; |
966 | + |
967 | + add_track(uri1); |
968 | + add_track(uri2); |
969 | + |
970 | + const size_t initial_size = m_hubTrackList->tracks().get().size(); |
971 | + cout << "Tracklist size: " << initial_size << endl; |
972 | + detach_player_session(uuid); |
973 | + reattach_player_session(uuid); |
974 | + cout << "Tracklist size: " << m_hubTrackList->tracks().get().size() << endl; |
975 | + |
976 | + m_hubPlayerSession->play(); |
977 | + |
978 | + if (initial_size != m_hubTrackList->tracks().get().size()) |
979 | + cout << "Tracklist sizes are different, error in resuming" << endl; |
980 | } |
981 | |
982 | void media::TestTrackList::test_ensure_tracklist_is_not_empty(const std::string &uri1, const std::string &uri2) |
983 | { |
984 | cout << "--> Running test: test_ensure_tracklist_is_not_empty" << std::endl; |
985 | |
986 | + const std::string uuid = create_new_player_session(); |
987 | + |
988 | add_track(uri1); |
989 | if (!uri2.empty()) |
990 | add_track(uri2); |
991 | @@ -133,13 +195,15 @@ |
992 | cout << "TrackList is not empty, test success" << endl; |
993 | else |
994 | cout << "TrackList is empty, test failure" << endl; |
995 | + |
996 | + destroy_player_session(uuid); |
997 | } |
998 | |
999 | void media::TestTrackList::test_has_next_track(const std::string &uri1, const std::string &uri2) |
1000 | { |
1001 | cout << "--> Running test: test_has_next_track" << std::endl; |
1002 | |
1003 | - //create_new_player_session(); |
1004 | + const std::string uuid = create_new_player_session(); |
1005 | |
1006 | add_track(uri1); |
1007 | add_track(uri2); |
1008 | @@ -158,13 +222,15 @@ |
1009 | else |
1010 | cerr << "Playback did not start successfully" << endl; |
1011 | |
1012 | - //destroy_player_session(); |
1013 | + destroy_player_session(uuid); |
1014 | } |
1015 | |
1016 | void media::TestTrackList::test_shuffle(const std::string &uri1, const std::string &uri2, const std::string &uri3) |
1017 | { |
1018 | cout << "--> Running test: test_shuffle" << std::endl; |
1019 | |
1020 | + const std::string uuid = create_new_player_session(); |
1021 | + |
1022 | add_track(uri1); |
1023 | add_track(uri2); |
1024 | add_track(uri3); |
1025 | @@ -189,22 +255,27 @@ |
1026 | cout << "Waiting for second track to finish playing..." << endl; |
1027 | wait_for_about_to_finish(); |
1028 | |
1029 | - cout << "Going straight to the Track with Id of '/core/ubuntu/media/Service/sessions/0/TrackList/4'" << std::endl; |
1030 | - const media::Track::Id id{"/core/ubuntu/media/Service/sessions/0/TrackList/4"}; |
1031 | + const media::Track::Id id{m_hubTrackList->tracks().get()[3]}; |
1032 | + cout << "Going straight to the Track with Id " << id << std::endl; |
1033 | const bool toggle_player_state = true; |
1034 | m_hubTrackList->go_to(id, toggle_player_state); |
1035 | + |
1036 | cout << "Waiting for third track to finish playing..." << endl; |
1037 | wait_for_about_to_finish(); |
1038 | } |
1039 | else |
1040 | cerr << "Playback did not start successfully" << endl; |
1041 | + |
1042 | + destroy_player_session(uuid); |
1043 | } |
1044 | |
1045 | void media::TestTrackList::test_remove_track(const std::string &uri1, const std::string &uri2, const std::string &uri3) |
1046 | { |
1047 | cout << "--> Running test: test_remove_track" << std::endl; |
1048 | |
1049 | - core::Connection c =m_hubTrackList->on_track_removed().connect([](const media::Track::Id &new_id) |
1050 | + const std::string uuid = create_new_player_session(); |
1051 | + |
1052 | + core::Connection c = m_hubTrackList->on_track_removed().connect([](const media::Track::Id &new_id) |
1053 | { |
1054 | cout << "Removed track from TrackList with Id: " << new_id << endl; |
1055 | }); |
1056 | @@ -220,7 +291,8 @@ |
1057 | cout << "Waiting for first track to finish playing..." << endl; |
1058 | wait_for_about_to_finish(); |
1059 | |
1060 | - const media::Track::Id id{"/core/ubuntu/media/Service/sessions/0/TrackList/1"}; |
1061 | + const media::Track::Id id{m_hubTrackList->tracks().get()[1]}; |
1062 | + cout << "Removing Track with Id of '" << id << "'" << std::endl; |
1063 | m_hubTrackList->remove_track(id); |
1064 | |
1065 | cout << "Waiting for track after removed track to finish playing..." << endl; |
1066 | @@ -228,6 +300,8 @@ |
1067 | } |
1068 | else |
1069 | cerr << "Playback did not start successfully" << endl; |
1070 | + |
1071 | + destroy_player_session(uuid); |
1072 | } |
1073 | |
1074 | template<class T> |
1075 | @@ -316,26 +390,31 @@ |
1076 | |
1077 | if (argc == 2) |
1078 | { |
1079 | - tracklist->create_new_player_session(); |
1080 | tracklist->test_basic_playback(argv[1]); |
1081 | tracklist->test_ensure_tracklist_is_not_empty(argv[1]); |
1082 | } |
1083 | else if (argc == 3) |
1084 | { |
1085 | - tracklist->create_new_player_session(); |
1086 | tracklist->test_basic_playback(argv[1], argv[2]); |
1087 | tracklist->test_ensure_tracklist_is_not_empty(argv[1], argv[2]); |
1088 | tracklist->test_has_next_track(argv[1], argv[2]); |
1089 | } |
1090 | else if (argc == 4) |
1091 | { |
1092 | - tracklist->create_new_player_session(); |
1093 | tracklist->test_basic_playback(argv[1]); |
1094 | tracklist->test_ensure_tracklist_is_not_empty(argv[1], argv[2]); |
1095 | tracklist->test_has_next_track(argv[1], argv[2]); |
1096 | tracklist->test_shuffle(argv[1], argv[2], argv[3]); |
1097 | tracklist->test_remove_track(argv[1], argv[2], argv[3]); |
1098 | } |
1099 | + else if (argc == 5) |
1100 | + { |
1101 | + std::string uuid = tracklist->create_new_player_session(); |
1102 | + |
1103 | + tracklist->test_tracklist_resume(argv[1], argv[2], uuid); |
1104 | + |
1105 | + tracklist->destroy_player_session(uuid); |
1106 | + } |
1107 | else |
1108 | { |
1109 | cout << "Can't test TrackList, no track(s) specified." << endl; |
1110 | |
1111 | === modified file 'tests/test-track-list/test_track_list.h' |
1112 | --- tests/test-track-list/test_track_list.h 2015-04-20 15:56:34 +0000 |
1113 | +++ tests/test-track-list/test_track_list.h 2015-04-20 15:56:34 +0000 |
1114 | @@ -45,14 +45,19 @@ |
1115 | TestTrackList(); |
1116 | ~TestTrackList(); |
1117 | |
1118 | - void create_new_player_session(); |
1119 | - void destroy_player_session(); |
1120 | + std::string create_new_player_session(); |
1121 | + void detach_player_session(const std::string &uuid); |
1122 | + void reattach_player_session(const std::string &uuid); |
1123 | + void destroy_player_session(const std::string &uuid); |
1124 | |
1125 | void add_track(const std::string &uri, bool make_current = false); |
1126 | |
1127 | // Takes in one or two files for playback, adds it/them to the TrackList, and plays |
1128 | void test_basic_playback(const std::string &uri1, const std::string &uri2 = std::string{}); |
1129 | |
1130 | + // Takes two uris and confirms that they remain after a detach/reattach |
1131 | + void test_tracklist_resume(const std::string &uri1, const std::string &uri2, const std::string &uuid); |
1132 | + |
1133 | void test_ensure_tracklist_is_not_empty(const std::string &uri1, const std::string &uri2 = std::string{}); |
1134 | |
1135 | // Takes in one or two files for playback, adds it/them to the TrackList, plays and makes sure |
FAILED: Continuous integration, rev:139 /code.launchpad .net/~ricmm/ media-hub/ session- reattach- nonfixed/ +merge/ 256101/ +edit-commit- message
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https:/
http:// jenkins. qa.ubuntu. com/job/ media-hub- ci/325/ jenkins. qa.ubuntu. com/job/ media-hub- vivid-amd64- ci/165/ console jenkins. qa.ubuntu. com/job/ media-hub- vivid-armhf- ci/165/ console jenkins. qa.ubuntu. com/job/ media-hub- vivid-i386- ci/165/ console
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/media- hub-ci/ 325/rebuild
http://