Merge lp:~jhodapp/media-hub/fix-zero-position-while-seeking into lp:media-hub
- fix-zero-position-while-seeking
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Ricardo Mendoza |
Approved revision: | 124 |
Merged at revision: | 126 |
Proposed branch: | lp:~jhodapp/media-hub/fix-zero-position-while-seeking |
Merge into: | lp:media-hub |
Prerequisite: | lp:~thomas-voss/media-hub/decouple-player-skeleton-and-implementation |
Diff against target: |
3163 lines (+1445/-633) 34 files modified
debian/changelog (+6/-9) debian/control (+0/-6) include/core/media/player.h (+1/-0) src/core/media/CMakeLists.txt (+6/-2) src/core/media/apparmor.h (+0/-93) src/core/media/apparmor/context.cpp (+34/-0) src/core/media/apparmor/context.h (+51/-0) src/core/media/apparmor/dbus.h (+94/-0) src/core/media/apparmor/ubuntu.cpp (+198/-0) src/core/media/apparmor/ubuntu.h (+167/-0) src/core/media/gstreamer/engine.cpp (+3/-3) src/core/media/gstreamer/playbin.cpp (+23/-6) src/core/media/gstreamer/playbin.h (+2/-0) src/core/media/hashed_keyed_player_store.cpp (+80/-0) src/core/media/hashed_keyed_player_store.h (+76/-0) src/core/media/keyed_player_store.h (+83/-0) src/core/media/mpris/player.h (+3/-0) src/core/media/null_track_list.h (+114/-0) src/core/media/player.cpp (+0/-1) src/core/media/player_configuration.h (+0/-3) src/core/media/player_implementation.cpp (+104/-81) src/core/media/player_implementation.h (+9/-9) src/core/media/player_skeleton.cpp (+35/-93) src/core/media/player_skeleton.h (+22/-16) src/core/media/player_stub.cpp (+18/-0) src/core/media/player_stub.h (+1/-0) src/core/media/power/state_controller.cpp (+21/-25) src/core/media/server/server.cpp (+19/-4) src/core/media/service_implementation.cpp (+35/-27) src/core/media/service_implementation.h (+2/-1) src/core/media/service_skeleton.cpp (+125/-174) src/core/media/service_skeleton.h (+14/-25) src/core/media/telephony/call_monitor.cpp (+56/-37) src/core/media/telephony/call_monitor.h (+43/-18) |
To merge this branch: | bzr merge lp:~jhodapp/media-hub/fix-zero-position-while-seeking |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Approve | |
Ubuntu Phablet Team | Pending | ||
Review via email:
|
Commit message
* Prevent a 0 position from being reported to the app which happens while seeking. Covers bad behavior that happens from GStreamer. Also expose the about_to_finish signal to the client.
* Enable playback again after manually seeking all the way to EOS. Also only send VideoDimensions
Description of the change
* Prevent a 0 position from being reported to the app which happens while seeking. Covers bad behavior that happens from GStreamer. Also expose the about_to_finish signal to the client.
* Enable playback again after manually seeking all the way to EOS. Also only send VideoDimensions
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
- 122. By Jim Hodapp
-
Merged prereqs.
- 123. By Jim Hodapp
-
Merge prereqs.
- 124. By Jim Hodapp
-
Fix the last merge.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:124
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'debian/changelog' | |||
2 | --- debian/changelog 2015-03-16 15:38:27 +0000 | |||
3 | +++ debian/changelog 2015-03-16 15:38:27 +0000 | |||
4 | @@ -1,4 +1,9 @@ | |||
6 | 1 | <<<<<<< TREE | 1 | media-hub (3.0.0) UNRELEASED; urgency=medium |
7 | 2 | |||
8 | 3 | * Refactor client-facing interfaces to pull out explicit dependency on hybris-based media layer. | ||
9 | 4 | |||
10 | 5 | -- Thomas Voss <thomas.voss@canonical.com> Tue, 11 Nov 2014 17:15:52 +0100 | ||
11 | 6 | |||
12 | 2 | media-hub (2.0.0+15.04.20150303-0ubuntu2) vivid; urgency=medium | 7 | media-hub (2.0.0+15.04.20150303-0ubuntu2) vivid; urgency=medium |
13 | 3 | 8 | ||
14 | 4 | * debian/control: | 9 | * debian/control: |
15 | @@ -17,14 +22,6 @@ | |||
16 | 17 | 22 | ||
17 | 18 | -- CI Train Bot <ci-train-bot@canonical.com> Tue, 03 Mar 2015 22:56:52 +0000 | 23 | -- CI Train Bot <ci-train-bot@canonical.com> Tue, 03 Mar 2015 22:56:52 +0000 |
18 | 19 | 24 | ||
19 | 20 | ======= | ||
20 | 21 | media-hub (3.0.0) UNRELEASED; urgency=medium | ||
21 | 22 | |||
22 | 23 | * Refactor client-facing interfaces to pull out explicit dependency on hybris-based media layer. | ||
23 | 24 | |||
24 | 25 | -- Thomas Voss <thomas.voss@canonical.com> Tue, 11 Nov 2014 17:15:52 +0100 | ||
25 | 26 | |||
26 | 27 | >>>>>>> MERGE-SOURCE | ||
27 | 28 | media-hub (2.0.0+15.04.20150120-0ubuntu1) vivid; urgency=low | 25 | media-hub (2.0.0+15.04.20150120-0ubuntu1) vivid; urgency=low |
28 | 29 | 26 | ||
29 | 30 | [ Jim Hodapp ] | 27 | [ Jim Hodapp ] |
30 | 31 | 28 | ||
31 | === modified file 'debian/control' | |||
32 | --- debian/control 2015-03-16 15:38:27 +0000 | |||
33 | +++ debian/control 2015-03-16 15:38:27 +0000 | |||
34 | @@ -39,14 +39,8 @@ | |||
35 | 39 | Section: libdevel | 39 | Section: libdevel |
36 | 40 | Architecture: any | 40 | Architecture: any |
37 | 41 | Multi-Arch: same | 41 | Multi-Arch: same |
38 | 42 | <<<<<<< TREE | ||
39 | 43 | Depends: libmedia-hub-common2 (= ${binary:Version}), | ||
40 | 44 | libmedia-hub-client2 (= ${binary:Version}), | ||
41 | 45 | ======= | ||
42 | 46 | Pre-Depends: dpkg (>= 1.15.6~) | ||
43 | 47 | Depends: libmedia-hub-common3 (= ${binary:Version}), | 42 | Depends: libmedia-hub-common3 (= ${binary:Version}), |
44 | 48 | libmedia-hub-client3 (= ${binary:Version}), | 43 | libmedia-hub-client3 (= ${binary:Version}), |
45 | 49 | >>>>>>> MERGE-SOURCE | ||
46 | 50 | ${misc:Depends}, | 44 | ${misc:Depends}, |
47 | 51 | libproperties-cpp-dev, | 45 | libproperties-cpp-dev, |
48 | 52 | Suggests: libmedia-hub-doc | 46 | Suggests: libmedia-hub-doc |
49 | 53 | 47 | ||
50 | === modified file 'include/core/media/player.h' | |||
51 | --- include/core/media/player.h 2015-03-16 15:38:27 +0000 | |||
52 | +++ include/core/media/player.h 2015-03-16 15:38:27 +0000 | |||
53 | @@ -168,6 +168,7 @@ | |||
54 | 168 | virtual core::Property<Lifetime>& lifetime() = 0; | 168 | virtual core::Property<Lifetime>& lifetime() = 0; |
55 | 169 | 169 | ||
56 | 170 | virtual const core::Signal<int64_t>& seeked_to() const = 0; | 170 | virtual const core::Signal<int64_t>& seeked_to() const = 0; |
57 | 171 | virtual const core::Signal<void>& about_to_finish() const = 0; | ||
58 | 171 | virtual const core::Signal<void>& end_of_stream() const = 0; | 172 | virtual const core::Signal<void>& end_of_stream() const = 0; |
59 | 172 | virtual core::Signal<PlaybackStatus>& playback_status_changed() = 0; | 173 | virtual core::Signal<PlaybackStatus>& playback_status_changed() = 0; |
60 | 173 | virtual const core::Signal<video::Dimensions>& video_dimension_changed() const = 0; | 174 | virtual const core::Signal<video::Dimensions>& video_dimension_changed() const = 0; |
61 | 174 | 175 | ||
62 | === modified file 'src/core/media/CMakeLists.txt' | |||
63 | --- src/core/media/CMakeLists.txt 2015-03-16 15:38:27 +0000 | |||
64 | +++ src/core/media/CMakeLists.txt 2015-03-16 15:38:27 +0000 | |||
65 | @@ -11,7 +11,7 @@ | |||
66 | 11 | 11 | ||
67 | 12 | message(STATUS ${MEDIA_HUB_HEADERS}) | 12 | message(STATUS ${MEDIA_HUB_HEADERS}) |
68 | 13 | 13 | ||
70 | 14 | add_subdirectory(call-monitor) | 14 | add_subdirectory(telephony) |
71 | 15 | 15 | ||
72 | 16 | add_library( | 16 | add_library( |
73 | 17 | media-hub-common SHARED | 17 | media-hub-common SHARED |
74 | @@ -87,10 +87,14 @@ | |||
75 | 87 | ${MPRIS_HEADERS} | 87 | ${MPRIS_HEADERS} |
76 | 88 | 88 | ||
77 | 89 | client_death_observer.cpp | 89 | client_death_observer.cpp |
79 | 90 | hybris_client_death_observer.cpp | 90 | hashed_keyed_player_store.cpp |
80 | 91 | hybris_client_death_observer.cpp | ||
81 | 91 | cover_art_resolver.cpp | 92 | cover_art_resolver.cpp |
82 | 92 | engine.cpp | 93 | engine.cpp |
83 | 93 | 94 | ||
84 | 95 | apparmor/context.cpp | ||
85 | 96 | apparmor/ubuntu.cpp | ||
86 | 97 | |||
87 | 94 | audio/pulse_audio_output_observer.cpp | 98 | audio/pulse_audio_output_observer.cpp |
88 | 95 | audio/ostream_reporter.cpp | 99 | audio/ostream_reporter.cpp |
89 | 96 | audio/output_observer.cpp | 100 | audio/output_observer.cpp |
90 | 97 | 101 | ||
91 | === added directory 'src/core/media/apparmor' | |||
92 | === removed file 'src/core/media/apparmor.h' | |||
93 | --- src/core/media/apparmor.h 2014-09-01 07:49:45 +0000 | |||
94 | +++ src/core/media/apparmor.h 1970-01-01 00:00:00 +0000 | |||
95 | @@ -1,93 +0,0 @@ | |||
96 | 1 | /* | ||
97 | 2 | * Copyright (C) 2013-2014 Canonical Ltd | ||
98 | 3 | * | ||
99 | 4 | * This program is free software: you can redistribute it and/or modify | ||
100 | 5 | * it under the terms of the GNU Lesser General Public License version 3 as | ||
101 | 6 | * published by the Free Software Foundation. | ||
102 | 7 | * | ||
103 | 8 | * This program is distributed in the hope that it will be useful, | ||
104 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
105 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
106 | 11 | * GNU Lesser General Public License for more details. | ||
107 | 12 | * | ||
108 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
109 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
110 | 15 | * | ||
111 | 16 | * Author: Jim Hodapp <jim.hodapp@canonical.com> | ||
112 | 17 | */ | ||
113 | 18 | |||
114 | 19 | #ifndef APPARMOR_DBUS_H_ | ||
115 | 20 | #define APPARMOR_DBUS_H_ | ||
116 | 21 | |||
117 | 22 | #include <core/dbus/macros.h> | ||
118 | 23 | #include <core/dbus/object.h> | ||
119 | 24 | #include <core/dbus/service.h> | ||
120 | 25 | |||
121 | 26 | #include <string> | ||
122 | 27 | #include <chrono> | ||
123 | 28 | |||
124 | 29 | // TODO(tvoss): This really should live in trust-store, providing a straightforward | ||
125 | 30 | // way for parties involved in managing trust relationships to query peers' apparmor | ||
126 | 31 | // profiles. Please see https://bugs.launchpad.net/trust-store/+bug/1350736 for the | ||
127 | 32 | // related bug | ||
128 | 33 | namespace org | ||
129 | 34 | { | ||
130 | 35 | namespace freedesktop | ||
131 | 36 | { | ||
132 | 37 | namespace dbus | ||
133 | 38 | { | ||
134 | 39 | struct DBus | ||
135 | 40 | { | ||
136 | 41 | static const std::string& name() | ||
137 | 42 | { | ||
138 | 43 | static const std::string s = "org.freedesktop.DBus"; | ||
139 | 44 | return s; | ||
140 | 45 | } | ||
141 | 46 | |||
142 | 47 | // Gets the AppArmor confinement string associated with the unique connection name. If | ||
143 | 48 | // D-Bus is not performing AppArmor mediation, the | ||
144 | 49 | // org.freedesktop.DBus.Error.AppArmorSecurityContextUnknown error is returned. | ||
145 | 50 | DBUS_CPP_METHOD_DEF(GetConnectionAppArmorSecurityContext, DBus) | ||
146 | 51 | |||
147 | 52 | struct Stub | ||
148 | 53 | { | ||
149 | 54 | // Creates a new stub instance for the given object to access | ||
150 | 55 | // DBus functionality. | ||
151 | 56 | Stub(const core::dbus::Object::Ptr& object) : object{object} | ||
152 | 57 | { | ||
153 | 58 | } | ||
154 | 59 | |||
155 | 60 | // Creates a new stub instance for the given bus connection | ||
156 | 61 | Stub(const core::dbus::Bus::Ptr& bus) | ||
157 | 62 | : object | ||
158 | 63 | { | ||
159 | 64 | core::dbus::Service::use_service<org::freedesktop::dbus::DBus>(bus) | ||
160 | 65 | ->object_for_path(core::dbus::types::ObjectPath{"/org/freedesktop/DBus"}) | ||
161 | 66 | } | ||
162 | 67 | { | ||
163 | 68 | } | ||
164 | 69 | |||
165 | 70 | // Gets the AppArmor confinement string associated with the unique connection name. If | ||
166 | 71 | // D-Bus is not performing AppArmor mediation, the | ||
167 | 72 | // org.freedesktop.DBus.Error.AppArmorSecurityContextUnknown error is returned. | ||
168 | 73 | // | ||
169 | 74 | // Invokes the given handler on completion. | ||
170 | 75 | void get_connection_app_armor_security_async( | ||
171 | 76 | const std::string& name, | ||
172 | 77 | std::function<void(const std::string&)> handler) | ||
173 | 78 | { | ||
174 | 79 | object->invoke_method_asynchronously_with_callback<GetConnectionAppArmorSecurityContext, std::string>( | ||
175 | 80 | [handler](const core::dbus::Result<std::string>& result) | ||
176 | 81 | { | ||
177 | 82 | if (not result.is_error()) handler(result.value()); | ||
178 | 83 | }, name); | ||
179 | 84 | } | ||
180 | 85 | |||
181 | 86 | core::dbus::Object::Ptr object; | ||
182 | 87 | }; | ||
183 | 88 | }; | ||
184 | 89 | } | ||
185 | 90 | } | ||
186 | 91 | } | ||
187 | 92 | |||
188 | 93 | #endif // APPARMOR_DBUS_H_ | ||
189 | 94 | 0 | ||
190 | === added file 'src/core/media/apparmor/context.cpp' | |||
191 | --- src/core/media/apparmor/context.cpp 1970-01-01 00:00:00 +0000 | |||
192 | +++ src/core/media/apparmor/context.cpp 2015-03-16 15:38:27 +0000 | |||
193 | @@ -0,0 +1,34 @@ | |||
194 | 1 | /* | ||
195 | 2 | * Copyright © 2014 Canonical Ltd. | ||
196 | 3 | * | ||
197 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
198 | 5 | * under the terms of the GNU Lesser General Public License version 3, | ||
199 | 6 | * as published by the Free Software Foundation. | ||
200 | 7 | * | ||
201 | 8 | * This program is distributed in the hope that it will be useful, | ||
202 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
203 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
204 | 11 | * GNU Lesser General Public License for more details. | ||
205 | 12 | * | ||
206 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
207 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
208 | 15 | * | ||
209 | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> | ||
210 | 17 | */ | ||
211 | 18 | |||
212 | 19 | #include <core/media/apparmor/context.h> | ||
213 | 20 | |||
214 | 21 | namespace apparmor = core::ubuntu::media::apparmor; | ||
215 | 22 | |||
216 | 23 | apparmor::Context::Context(const std::string& name) : name{name} | ||
217 | 24 | { | ||
218 | 25 | if (name.empty()) throw std::runtime_error | ||
219 | 26 | { | ||
220 | 27 | "apparmor::Context cannot be created for empty name." | ||
221 | 28 | }; | ||
222 | 29 | } | ||
223 | 30 | |||
224 | 31 | const std::string& apparmor::Context::str() const | ||
225 | 32 | { | ||
226 | 33 | return name; | ||
227 | 34 | } | ||
228 | 0 | 35 | ||
229 | === added file 'src/core/media/apparmor/context.h' | |||
230 | --- src/core/media/apparmor/context.h 1970-01-01 00:00:00 +0000 | |||
231 | +++ src/core/media/apparmor/context.h 2015-03-16 15:38:27 +0000 | |||
232 | @@ -0,0 +1,51 @@ | |||
233 | 1 | /* | ||
234 | 2 | * Copyright © 2014 Canonical Ltd. | ||
235 | 3 | * | ||
236 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
237 | 5 | * under the terms of the GNU Lesser General Public License version 3, | ||
238 | 6 | * as published by the Free Software Foundation. | ||
239 | 7 | * | ||
240 | 8 | * This program is distributed in the hope that it will be useful, | ||
241 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
242 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
243 | 11 | * GNU Lesser General Public License for more details. | ||
244 | 12 | * | ||
245 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
246 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
247 | 15 | * | ||
248 | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> | ||
249 | 17 | */ | ||
250 | 18 | #ifndef CORE_UBUNTU_MEDIA_APPARMOR_AUTHENTICATOR_H_ | ||
251 | 19 | #define CORE_UBUNTU_MEDIA_APPARMOR_AUTHENTICATOR_H_ | ||
252 | 20 | |||
253 | 21 | #include <memory> | ||
254 | 22 | #include <string> | ||
255 | 23 | |||
256 | 24 | namespace core | ||
257 | 25 | { | ||
258 | 26 | namespace ubuntu | ||
259 | 27 | { | ||
260 | 28 | namespace media | ||
261 | 29 | { | ||
262 | 30 | namespace apparmor | ||
263 | 31 | { | ||
264 | 32 | // Models an apparmor context name, and provides convenience functionality | ||
265 | 33 | // on top of it. | ||
266 | 34 | class Context | ||
267 | 35 | { | ||
268 | 36 | public: | ||
269 | 37 | // Constructs a new Context instance for the given raw name. | ||
270 | 38 | // Throws std::logic_error for empty names. | ||
271 | 39 | explicit Context(const std::string& name); | ||
272 | 40 | virtual ~Context() = default; | ||
273 | 41 | // Returns the raw string describing the context. | ||
274 | 42 | const std::string& str() const; | ||
275 | 43 | |||
276 | 44 | private: | ||
277 | 45 | const std::string name; | ||
278 | 46 | }; | ||
279 | 47 | } | ||
280 | 48 | } | ||
281 | 49 | } | ||
282 | 50 | } | ||
283 | 51 | #endif // CORE_UBUNTU_MEDIA_APPARMOR_AUTHENTICATOR_H_ | ||
284 | 0 | 52 | ||
285 | === added file 'src/core/media/apparmor/dbus.h' | |||
286 | --- src/core/media/apparmor/dbus.h 1970-01-01 00:00:00 +0000 | |||
287 | +++ src/core/media/apparmor/dbus.h 2015-03-16 15:38:27 +0000 | |||
288 | @@ -0,0 +1,94 @@ | |||
289 | 1 | /* | ||
290 | 2 | * Copyright (C) 2013-2014 Canonical Ltd | ||
291 | 3 | * | ||
292 | 4 | * This program is free software: you can redistribute it and/or modify | ||
293 | 5 | * it under the terms of the GNU Lesser General Public License version 3 as | ||
294 | 6 | * published by the Free Software Foundation. | ||
295 | 7 | * | ||
296 | 8 | * This program is distributed in the hope that it will be useful, | ||
297 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
298 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
299 | 11 | * GNU Lesser General Public License for more details. | ||
300 | 12 | * | ||
301 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
302 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
303 | 15 | * | ||
304 | 16 | * Author: Jim Hodapp <jim.hodapp@canonical.com> | ||
305 | 17 | */ | ||
306 | 18 | |||
307 | 19 | #ifndef CORE_UBUNTU_MEDIA_APPARMOR_DBUS_H_ | ||
308 | 20 | #define CORE_UBUNTU_MEDIA_APPARMOR_DBUS_H_ | ||
309 | 21 | |||
310 | 22 | #include <core/dbus/bus.h> | ||
311 | 23 | #include <core/dbus/macros.h> | ||
312 | 24 | #include <core/dbus/object.h> | ||
313 | 25 | #include <core/dbus/service.h> | ||
314 | 26 | |||
315 | 27 | #include <string> | ||
316 | 28 | #include <chrono> | ||
317 | 29 | |||
318 | 30 | // TODO(tvoss): This really should live in trust-store, providing a straightforward | ||
319 | 31 | // way for parties involved in managing trust relationships to query peers' apparmor | ||
320 | 32 | // profiles. Please see https://bugs.launchpad.net/trust-store/+bug/1350736 for the | ||
321 | 33 | // related bug | ||
322 | 34 | namespace org | ||
323 | 35 | { | ||
324 | 36 | namespace freedesktop | ||
325 | 37 | { | ||
326 | 38 | namespace dbus | ||
327 | 39 | { | ||
328 | 40 | struct DBus | ||
329 | 41 | { | ||
330 | 42 | static const std::string& name() | ||
331 | 43 | { | ||
332 | 44 | static const std::string s = "org.freedesktop.DBus"; | ||
333 | 45 | return s; | ||
334 | 46 | } | ||
335 | 47 | |||
336 | 48 | // Gets the AppArmor confinement string associated with the unique connection name. If | ||
337 | 49 | // D-Bus is not performing AppArmor mediation, the | ||
338 | 50 | // org.freedesktop.DBus.Error.AppArmorSecurityContextUnknown error is returned. | ||
339 | 51 | DBUS_CPP_METHOD_DEF(GetConnectionAppArmorSecurityContext, DBus) | ||
340 | 52 | |||
341 | 53 | struct Stub | ||
342 | 54 | { | ||
343 | 55 | // Creates a new stub instance for the given object to access | ||
344 | 56 | // DBus functionality. | ||
345 | 57 | Stub(const core::dbus::Object::Ptr& object) : object{object} | ||
346 | 58 | { | ||
347 | 59 | } | ||
348 | 60 | |||
349 | 61 | // Creates a new stub instance for the given bus connection | ||
350 | 62 | Stub(const core::dbus::Bus::Ptr& bus) | ||
351 | 63 | : object | ||
352 | 64 | { | ||
353 | 65 | core::dbus::Service::use_service<org::freedesktop::dbus::DBus>(bus) | ||
354 | 66 | ->object_for_path(core::dbus::types::ObjectPath{"/org/freedesktop/DBus"}) | ||
355 | 67 | } | ||
356 | 68 | { | ||
357 | 69 | } | ||
358 | 70 | |||
359 | 71 | // Gets the AppArmor confinement string associated with the unique connection name. If | ||
360 | 72 | // D-Bus is not performing AppArmor mediation, the | ||
361 | 73 | // org.freedesktop.DBus.Error.AppArmorSecurityContextUnknown error is returned. | ||
362 | 74 | // | ||
363 | 75 | // Invokes the given handler on completion. | ||
364 | 76 | void get_connection_app_armor_security_async( | ||
365 | 77 | const std::string& name, | ||
366 | 78 | std::function<void(const std::string&)> handler) | ||
367 | 79 | { | ||
368 | 80 | object->invoke_method_asynchronously_with_callback<GetConnectionAppArmorSecurityContext, std::string>( | ||
369 | 81 | [handler](const core::dbus::Result<std::string>& result) | ||
370 | 82 | { | ||
371 | 83 | if (not result.is_error()) handler(result.value()); | ||
372 | 84 | }, name); | ||
373 | 85 | } | ||
374 | 86 | |||
375 | 87 | core::dbus::Object::Ptr object; | ||
376 | 88 | }; | ||
377 | 89 | }; | ||
378 | 90 | } | ||
379 | 91 | } | ||
380 | 92 | } | ||
381 | 93 | |||
382 | 94 | #endif // CORE_UBUNTU_MEDIA_APPARMOR_DBUS_H_ | ||
383 | 0 | 95 | ||
384 | === added file 'src/core/media/apparmor/ubuntu.cpp' | |||
385 | --- src/core/media/apparmor/ubuntu.cpp 1970-01-01 00:00:00 +0000 | |||
386 | +++ src/core/media/apparmor/ubuntu.cpp 2015-03-16 15:38:27 +0000 | |||
387 | @@ -0,0 +1,198 @@ | |||
388 | 1 | /* | ||
389 | 2 | * Copyright © 2014 Canonical Ltd. | ||
390 | 3 | * | ||
391 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
392 | 5 | * under the terms of the GNU Lesser General Public License version 3, | ||
393 | 6 | * as published by the Free Software Foundation. | ||
394 | 7 | * | ||
395 | 8 | * This program is distributed in the hope that it will be useful, | ||
396 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
397 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
398 | 11 | * GNU Lesser General Public License for more details. | ||
399 | 12 | * | ||
400 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
401 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
402 | 15 | * | ||
403 | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> | ||
404 | 17 | */ | ||
405 | 18 | |||
406 | 19 | #include <core/media/apparmor/ubuntu.h> | ||
407 | 20 | |||
408 | 21 | #include <core/media/external_services.h> | ||
409 | 22 | |||
410 | 23 | #include <iostream> | ||
411 | 24 | #include <regex> | ||
412 | 25 | |||
413 | 26 | namespace apparmor = core::ubuntu::media::apparmor; | ||
414 | 27 | namespace media = core::ubuntu::media; | ||
415 | 28 | namespace ubuntu = apparmor::ubuntu; | ||
416 | 29 | |||
417 | 30 | namespace | ||
418 | 31 | { | ||
419 | 32 | struct Uri | ||
420 | 33 | { | ||
421 | 34 | std::string scheme; | ||
422 | 35 | std::string authority; | ||
423 | 36 | std::string path; | ||
424 | 37 | std::string query; | ||
425 | 38 | std::string fragment; | ||
426 | 39 | }; | ||
427 | 40 | |||
428 | 41 | // Poor mans version of a uri parser. | ||
429 | 42 | // See https://tools.ietf.org/html/rfc3986#appendix-B | ||
430 | 43 | Uri parse_uri(const std::string& s) | ||
431 | 44 | { | ||
432 | 45 | // Indices into the regex match go here. | ||
433 | 46 | struct Index | ||
434 | 47 | { | ||
435 | 48 | const std::size_t scheme{2}; | ||
436 | 49 | const std::size_t authority{4}; | ||
437 | 50 | const std::size_t path{5}; | ||
438 | 51 | const std::size_t query{7}; | ||
439 | 52 | const std::size_t fragment{9}; | ||
440 | 53 | } static index; | ||
441 | 54 | |||
442 | 55 | static const std::regex regex{R"delim(^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?)delim"}; | ||
443 | 56 | std::smatch match; | ||
444 | 57 | |||
445 | 58 | if (not std::regex_match(s, match, regex)) throw std::runtime_error | ||
446 | 59 | { | ||
447 | 60 | "Not a valid URI: " + s | ||
448 | 61 | }; | ||
449 | 62 | |||
450 | 63 | return Uri | ||
451 | 64 | { | ||
452 | 65 | match.str(index.scheme), | ||
453 | 66 | match.str(index.authority), | ||
454 | 67 | match.str(index.path), | ||
455 | 68 | match.str(index.query), | ||
456 | 69 | match.str(index.fragment) | ||
457 | 70 | }; | ||
458 | 71 | } | ||
459 | 72 | |||
460 | 73 | static constexpr std::size_t index_package{1}; | ||
461 | 74 | static constexpr std::size_t index_app{2}; | ||
462 | 75 | |||
463 | 76 | // Returns true if the context name is a valid Ubuntu app id. | ||
464 | 77 | // If it is, out is populated with the package and app name. | ||
465 | 78 | bool process_context_name(const std::string& s, std::smatch& out) | ||
466 | 79 | { | ||
467 | 80 | // See https://wiki.ubuntu.com/AppStore/Interfaces/ApplicationId. | ||
468 | 81 | static const std::regex short_re{"(.*)_(.*)"}; | ||
469 | 82 | static const std::regex full_re{"(.*)_(.*)_(.*)"}; | ||
470 | 83 | |||
471 | 84 | if (std::regex_match(s, out, full_re)) | ||
472 | 85 | return true; | ||
473 | 86 | |||
474 | 87 | if (std::regex_match(s, out, short_re)) | ||
475 | 88 | return true; | ||
476 | 89 | |||
477 | 90 | return false; | ||
478 | 91 | } | ||
479 | 92 | } | ||
480 | 93 | |||
481 | 94 | apparmor::ubuntu::Context::Context(const std::string& name) | ||
482 | 95 | : apparmor::Context{name}, | ||
483 | 96 | unconfined_{str() == ubuntu::unconfined}, | ||
484 | 97 | has_package_name_{process_context_name(str(), match_)} | ||
485 | 98 | { | ||
486 | 99 | if (not is_unconfined() && not has_package_name()) throw std::logic_error | ||
487 | 100 | { | ||
488 | 101 | "apparmor::ubuntu::Context: Invalid profile name " + str() | ||
489 | 102 | }; | ||
490 | 103 | } | ||
491 | 104 | |||
492 | 105 | bool apparmor::ubuntu::Context::is_unconfined() const | ||
493 | 106 | { | ||
494 | 107 | return unconfined_; | ||
495 | 108 | } | ||
496 | 109 | |||
497 | 110 | bool apparmor::ubuntu::Context::has_package_name() const | ||
498 | 111 | { | ||
499 | 112 | return has_package_name_; | ||
500 | 113 | } | ||
501 | 114 | |||
502 | 115 | |||
503 | 116 | std::string apparmor::ubuntu::Context::package_name() const | ||
504 | 117 | { | ||
505 | 118 | return std::string{match_[index_package]}; | ||
506 | 119 | } | ||
507 | 120 | |||
508 | 121 | apparmor::ubuntu::DBusDaemonRequestContextResolver::DBusDaemonRequestContextResolver(const core::dbus::Bus::Ptr& bus) : dbus_daemon{bus} | ||
509 | 122 | { | ||
510 | 123 | } | ||
511 | 124 | |||
512 | 125 | void apparmor::ubuntu::DBusDaemonRequestContextResolver::resolve_context_for_dbus_name_async( | ||
513 | 126 | const std::string& name, | ||
514 | 127 | apparmor::ubuntu::RequestContextResolver::ResolveCallback cb) | ||
515 | 128 | { | ||
516 | 129 | dbus_daemon.get_connection_app_armor_security_async(name, [cb](const std::string& context_name) | ||
517 | 130 | { | ||
518 | 131 | cb(apparmor::ubuntu::Context{context_name}); | ||
519 | 132 | }); | ||
520 | 133 | } | ||
521 | 134 | |||
522 | 135 | apparmor::ubuntu::RequestAuthenticator::Result apparmor::ubuntu::ExistingAuthenticator::authenticate_open_uri_request(const apparmor::ubuntu::Context& context, const std::string& uri) | ||
523 | 136 | { | ||
524 | 137 | if (context.is_unconfined()) | ||
525 | 138 | return Result{true, "Client allowed access since it's unconfined"}; | ||
526 | 139 | |||
527 | 140 | Uri parsed_uri = parse_uri(uri); | ||
528 | 141 | |||
529 | 142 | // All confined apps can access their own files | ||
530 | 143 | if (parsed_uri.path.find(std::string(".local/share/" + context.package_name() + "/")) != std::string::npos || | ||
531 | 144 | parsed_uri.path.find(std::string(".cache/" + context.package_name() + "/")) != std::string::npos) | ||
532 | 145 | { | ||
533 | 146 | return Result | ||
534 | 147 | { | ||
535 | 148 | true, | ||
536 | 149 | "Client can access content in ~/.local/share/" + context.package_name() + " or ~/.cache/" + context.package_name() | ||
537 | 150 | }; | ||
538 | 151 | } | ||
539 | 152 | else if (parsed_uri.path.find(std::string("opt/click.ubuntu.com/")) != std::string::npos && | ||
540 | 153 | parsed_uri.path.find(context.package_name()) != std::string::npos) | ||
541 | 154 | { | ||
542 | 155 | return Result{true, "Client can access content in own opt directory"}; | ||
543 | 156 | } | ||
544 | 157 | else if ((parsed_uri.path.find(std::string("/system/media/audio/ui/")) != std::string::npos || | ||
545 | 158 | parsed_uri.path.find(std::string("/android/system/media/audio/ui/")) != std::string::npos) && | ||
546 | 159 | context.package_name() == "com.ubuntu.camera") | ||
547 | 160 | { | ||
548 | 161 | return Result{true, "Camera app can access ui sounds"}; | ||
549 | 162 | } | ||
550 | 163 | |||
551 | 164 | // TODO: Check if the trust store previously allowed direct access to uri | ||
552 | 165 | |||
553 | 166 | // Check in ~/Music and ~/Videos | ||
554 | 167 | // TODO: when the trust store lands, check it to see if this app can access the dirs and | ||
555 | 168 | // then remove the explicit whitelist of the music-app, and gallery-app | ||
556 | 169 | else if ((context.package_name() == "com.ubuntu.music" || context.package_name() == "com.ubuntu.gallery") && | ||
557 | 170 | (parsed_uri.path.find(std::string("Music/")) != std::string::npos || | ||
558 | 171 | parsed_uri.path.find(std::string("Videos/")) != std::string::npos || | ||
559 | 172 | parsed_uri.path.find(std::string("/media")) != std::string::npos)) | ||
560 | 173 | { | ||
561 | 174 | return Result{true, "Client can access content in ~/Music or ~/Videos"}; | ||
562 | 175 | } | ||
563 | 176 | else if (parsed_uri.path.find(std::string("/usr/share/sounds")) != std::string::npos) | ||
564 | 177 | { | ||
565 | 178 | return Result{true, "Client can access content in /usr/share/sounds"}; | ||
566 | 179 | } | ||
567 | 180 | else if (parsed_uri.scheme == "http" || parsed_uri.scheme == "rtsp") | ||
568 | 181 | { | ||
569 | 182 | return Result{true, "Client can access streaming content"}; | ||
570 | 183 | } | ||
571 | 184 | |||
572 | 185 | return Result{false, "Client is not allowed to access: " + uri}; | ||
573 | 186 | } | ||
574 | 187 | |||
575 | 188 | // Returns the platform-default implementation of RequestContextResolver. | ||
576 | 189 | apparmor::ubuntu::RequestContextResolver::Ptr apparmor::ubuntu::make_platform_default_request_context_resolver(media::helper::ExternalServices& es) | ||
577 | 190 | { | ||
578 | 191 | return std::make_shared<apparmor::ubuntu::DBusDaemonRequestContextResolver>(es.session); | ||
579 | 192 | } | ||
580 | 193 | |||
581 | 194 | // Returns the platform-default implementation of RequestAuthenticator. | ||
582 | 195 | apparmor::ubuntu::RequestAuthenticator::Ptr apparmor::ubuntu::make_platform_default_request_authenticator() | ||
583 | 196 | { | ||
584 | 197 | return std::make_shared<apparmor::ubuntu::ExistingAuthenticator>(); | ||
585 | 198 | } | ||
586 | 0 | 199 | ||
587 | === added file 'src/core/media/apparmor/ubuntu.h' | |||
588 | --- src/core/media/apparmor/ubuntu.h 1970-01-01 00:00:00 +0000 | |||
589 | +++ src/core/media/apparmor/ubuntu.h 2015-03-16 15:38:27 +0000 | |||
590 | @@ -0,0 +1,167 @@ | |||
591 | 1 | /* | ||
592 | 2 | * Copyright © 2014 Canonical Ltd. | ||
593 | 3 | * | ||
594 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
595 | 5 | * under the terms of the GNU Lesser General Public License version 3, | ||
596 | 6 | * as published by the Free Software Foundation. | ||
597 | 7 | * | ||
598 | 8 | * This program is distributed in the hope that it will be useful, | ||
599 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
600 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
601 | 11 | * GNU Lesser General Public License for more details. | ||
602 | 12 | * | ||
603 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
604 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
605 | 15 | * | ||
606 | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> | ||
607 | 17 | */ | ||
608 | 18 | #ifndef CORE_UBUNTU_MEDIA_APPARMOR_UBUNTU_H_ | ||
609 | 19 | #define CORE_UBUNTU_MEDIA_APPARMOR_UBUNTU_H_ | ||
610 | 20 | |||
611 | 21 | #include <core/media/apparmor/context.h> | ||
612 | 22 | #include <core/media/apparmor/dbus.h> | ||
613 | 23 | |||
614 | 24 | #include <functional> | ||
615 | 25 | #include <memory> | ||
616 | 26 | #include <regex> | ||
617 | 27 | #include <string> | ||
618 | 28 | #include <vector> | ||
619 | 29 | |||
620 | 30 | namespace core | ||
621 | 31 | { | ||
622 | 32 | namespace dbus | ||
623 | 33 | { | ||
624 | 34 | class Bus; | ||
625 | 35 | } | ||
626 | 36 | |||
627 | 37 | namespace ubuntu | ||
628 | 38 | { | ||
629 | 39 | namespace media | ||
630 | 40 | { | ||
631 | 41 | namespace helper | ||
632 | 42 | { | ||
633 | 43 | struct ExternalServices; | ||
634 | 44 | } | ||
635 | 45 | namespace apparmor | ||
636 | 46 | { | ||
637 | 47 | // Collects Ubuntu-specific apparmor conventions, e.g., format | ||
638 | 48 | // of short and full package names as well as convenience functionality | ||
639 | 49 | // to inspect apparmor::Context instances. | ||
640 | 50 | namespace ubuntu | ||
641 | 51 | { | ||
642 | 52 | // The unconfined profile, unconditionally trusted | ||
643 | 53 | // by the system. | ||
644 | 54 | static constexpr const char* unconfined | ||
645 | 55 | { | ||
646 | 56 | "unconfined" | ||
647 | 57 | }; | ||
648 | 58 | |||
649 | 59 | class Context : public apparmor::Context | ||
650 | 60 | { | ||
651 | 61 | public: | ||
652 | 62 | // Constructs a new Context instance for the given raw name. | ||
653 | 63 | // Throws std::logic_error for empty names or for names not | ||
654 | 64 | // complying to Ubuntu conventions. | ||
655 | 65 | Context(const std::string& name); | ||
656 | 66 | |||
657 | 67 | // Returns true iff the context is unconfined. | ||
658 | 68 | virtual bool is_unconfined() const; | ||
659 | 69 | |||
660 | 70 | // Returns true iff the context contains a package name. | ||
661 | 71 | virtual bool has_package_name() const; | ||
662 | 72 | |||
663 | 73 | // Returns the package name or throws if no package name can be found. | ||
664 | 74 | virtual std::string package_name() const; | ||
665 | 75 | |||
666 | 76 | private: | ||
667 | 77 | std::smatch match_; | ||
668 | 78 | const bool unconfined_; | ||
669 | 79 | const bool has_package_name_; | ||
670 | 80 | }; | ||
671 | 81 | |||
672 | 82 | // Abstracts query for the apparmor context of an incoming request | ||
673 | 83 | class RequestContextResolver | ||
674 | 84 | { | ||
675 | 85 | public: | ||
676 | 86 | // To save us some typing. | ||
677 | 87 | typedef std::shared_ptr<RequestContextResolver> Ptr; | ||
678 | 88 | |||
679 | 89 | // Callback for resolve context operations. | ||
680 | 90 | typedef std::function<void(const Context&)> ResolveCallback; | ||
681 | 91 | |||
682 | 92 | // Resolves the given name (of a dbus participant) to its apparmor context, | ||
683 | 93 | // invoking the callback whenever a result is available. | ||
684 | 94 | virtual void resolve_context_for_dbus_name_async(const std::string& name, ResolveCallback cb) = 0; | ||
685 | 95 | |||
686 | 96 | protected: | ||
687 | 97 | RequestContextResolver() = default; | ||
688 | 98 | RequestContextResolver(const RequestContextResolver&) = delete; | ||
689 | 99 | virtual ~RequestContextResolver() = default; | ||
690 | 100 | RequestContextResolver& operator=(const RequestContextResolver&) = delete; | ||
691 | 101 | }; | ||
692 | 102 | |||
693 | 103 | // An implementation of RequestContextResolver that queries the dbus | ||
694 | 104 | // daemon to resolve the apparmor context. | ||
695 | 105 | class DBusDaemonRequestContextResolver : public RequestContextResolver | ||
696 | 106 | { | ||
697 | 107 | public: | ||
698 | 108 | // To save us some typing. | ||
699 | 109 | typedef std::shared_ptr<DBusDaemonRequestContextResolver> Ptr; | ||
700 | 110 | |||
701 | 111 | // Constructs a new instance for the given bus connection. | ||
702 | 112 | DBusDaemonRequestContextResolver(const core::dbus::Bus::Ptr &); | ||
703 | 113 | |||
704 | 114 | // From RequestContextResolver | ||
705 | 115 | void resolve_context_for_dbus_name_async(const std::string& name, ResolveCallback) override; | ||
706 | 116 | |||
707 | 117 | private: | ||
708 | 118 | org::freedesktop::dbus::DBus::Stub dbus_daemon; | ||
709 | 119 | }; | ||
710 | 120 | |||
711 | 121 | // Abstracts an apparmor-based authentication of | ||
712 | 122 | // incoming requests from clients. | ||
713 | 123 | class RequestAuthenticator | ||
714 | 124 | { | ||
715 | 125 | public: | ||
716 | 126 | // To save us some typing. | ||
717 | 127 | typedef std::shared_ptr<RequestAuthenticator> Ptr; | ||
718 | 128 | |||
719 | 129 | // Return type of an authentication call. | ||
720 | 130 | typedef std::tuple | ||
721 | 131 | < | ||
722 | 132 | bool, // True if authenticated, false if not. | ||
723 | 133 | std::string // Reason for the result. | ||
724 | 134 | > Result; | ||
725 | 135 | |||
726 | 136 | virtual ~RequestAuthenticator() = default; | ||
727 | 137 | |||
728 | 138 | // Returns true iff the client identified by the given apparmor::Context is allowed | ||
729 | 139 | // to access the given uri, false otherwise. | ||
730 | 140 | virtual Result authenticate_open_uri_request(const Context&, const std::string& uri) = 0; | ||
731 | 141 | |||
732 | 142 | protected: | ||
733 | 143 | RequestAuthenticator() = default; | ||
734 | 144 | RequestAuthenticator(const RequestAuthenticator&) = default; | ||
735 | 145 | RequestAuthenticator& operator=(const RequestAuthenticator&) = default; | ||
736 | 146 | }; | ||
737 | 147 | |||
738 | 148 | // Takes the existing logic and exposes it as an implementation | ||
739 | 149 | // of the RequestAuthenticator interface. | ||
740 | 150 | struct ExistingAuthenticator : public RequestAuthenticator | ||
741 | 151 | { | ||
742 | 152 | ExistingAuthenticator() = default; | ||
743 | 153 | // From RequestAuthenticator | ||
744 | 154 | Result authenticate_open_uri_request(const Context&, const std::string& uri) override; | ||
745 | 155 | }; | ||
746 | 156 | |||
747 | 157 | // Returns the platform-default implementation of RequestContextResolver. | ||
748 | 158 | RequestContextResolver::Ptr make_platform_default_request_context_resolver(helper::ExternalServices& es); | ||
749 | 159 | // Returns the platform-default implementation of RequestAuthenticator. | ||
750 | 160 | RequestAuthenticator::Ptr make_platform_default_request_authenticator(); | ||
751 | 161 | } | ||
752 | 162 | } | ||
753 | 163 | } | ||
754 | 164 | } | ||
755 | 165 | } | ||
756 | 166 | |||
757 | 167 | #endif // CORE_UBUNTU_MEDIA_APPARMOR_UBUNTU_H_ | ||
758 | 0 | 168 | ||
759 | === modified file 'src/core/media/gstreamer/engine.cpp' | |||
760 | --- src/core/media/gstreamer/engine.cpp 2015-03-16 15:38:27 +0000 | |||
761 | +++ src/core/media/gstreamer/engine.cpp 2015-03-16 15:38:27 +0000 | |||
762 | @@ -355,7 +355,7 @@ | |||
763 | 355 | if (result) | 355 | if (result) |
764 | 356 | { | 356 | { |
765 | 357 | d->state = media::Engine::State::playing; | 357 | d->state = media::Engine::State::playing; |
767 | 358 | cout << "play" << endl; | 358 | cout << __PRETTY_FUNCTION__ << endl; |
768 | 359 | d->playback_status_changed(media::Player::PlaybackStatus::playing); | 359 | d->playback_status_changed(media::Player::PlaybackStatus::playing); |
769 | 360 | } | 360 | } |
770 | 361 | 361 | ||
771 | @@ -373,7 +373,7 @@ | |||
772 | 373 | if (result) | 373 | if (result) |
773 | 374 | { | 374 | { |
774 | 375 | d->state = media::Engine::State::stopped; | 375 | d->state = media::Engine::State::stopped; |
776 | 376 | cout << "stop" << endl; | 376 | cout << __PRETTY_FUNCTION__ << endl; |
777 | 377 | d->playback_status_changed(media::Player::PlaybackStatus::stopped); | 377 | d->playback_status_changed(media::Player::PlaybackStatus::stopped); |
778 | 378 | } | 378 | } |
779 | 379 | 379 | ||
780 | @@ -387,7 +387,7 @@ | |||
781 | 387 | if (result) | 387 | if (result) |
782 | 388 | { | 388 | { |
783 | 389 | d->state = media::Engine::State::paused; | 389 | d->state = media::Engine::State::paused; |
785 | 390 | cout << "pause" << endl; | 390 | cout << __PRETTY_FUNCTION__ << endl; |
786 | 391 | d->playback_status_changed(media::Player::PlaybackStatus::paused); | 391 | d->playback_status_changed(media::Player::PlaybackStatus::paused); |
787 | 392 | } | 392 | } |
788 | 393 | 393 | ||
789 | 394 | 394 | ||
790 | === modified file 'src/core/media/gstreamer/playbin.cpp' | |||
791 | --- src/core/media/gstreamer/playbin.cpp 2015-03-16 15:38:27 +0000 | |||
792 | +++ src/core/media/gstreamer/playbin.cpp 2015-03-16 15:38:27 +0000 | |||
793 | @@ -97,11 +97,15 @@ | |||
794 | 97 | this, | 97 | this, |
795 | 98 | std::placeholders::_1))), | 98 | std::placeholders::_1))), |
796 | 99 | is_seeking(false), | 99 | is_seeking(false), |
798 | 100 | player_lifetime(media::Player::Lifetime::normal) | 100 | previous_position(0), |
799 | 101 | player_lifetime(media::Player::Lifetime::normal), | ||
800 | 102 | is_eos(false) | ||
801 | 101 | { | 103 | { |
802 | 102 | if (!pipeline) | 104 | if (!pipeline) |
803 | 103 | throw std::runtime_error("Could not create pipeline for playbin."); | 105 | throw std::runtime_error("Could not create pipeline for playbin."); |
804 | 104 | 106 | ||
805 | 107 | is_eos = false; | ||
806 | 108 | |||
807 | 105 | // Add audio and/or video sink elements depending on environment variables | 109 | // Add audio and/or video sink elements depending on environment variables |
808 | 106 | // being set or not set | 110 | // being set or not set |
809 | 107 | setup_pipeline_for_audio_video(); | 111 | setup_pipeline_for_audio_video(); |
810 | @@ -199,6 +203,7 @@ | |||
811 | 199 | } | 203 | } |
812 | 200 | break; | 204 | break; |
813 | 201 | case GST_MESSAGE_EOS: | 205 | case GST_MESSAGE_EOS: |
814 | 206 | is_eos = true; | ||
815 | 202 | signals.on_end_of_stream(); | 207 | signals.on_end_of_stream(); |
816 | 203 | default: | 208 | default: |
817 | 204 | break; | 209 | break; |
818 | @@ -334,6 +339,17 @@ | |||
819 | 334 | int64_t pos = 0; | 339 | int64_t pos = 0; |
820 | 335 | gst_element_query_position (pipeline, GST_FORMAT_TIME, &pos); | 340 | gst_element_query_position (pipeline, GST_FORMAT_TIME, &pos); |
821 | 336 | 341 | ||
822 | 342 | // This prevents a 0 position from being reported to the app which happens while seeking. | ||
823 | 343 | // This is covering over a GStreamer issue | ||
824 | 344 | if ((static_cast<uint64_t>(pos) < duration()) && is_seeking && pos == 0) | ||
825 | 345 | { | ||
826 | 346 | return previous_position; | ||
827 | 347 | } | ||
828 | 348 | |||
829 | 349 | // Save the current position to use just in case it's needed the next time position is | ||
830 | 350 | // requested | ||
831 | 351 | previous_position = static_cast<uint64_t>(pos); | ||
832 | 352 | |||
833 | 337 | // FIXME: this should be int64_t, but dbus-cpp doesn't seem to handle it correctly | 353 | // FIXME: this should be int64_t, but dbus-cpp doesn't seem to handle it correctly |
834 | 338 | return static_cast<uint64_t>(pos); | 354 | return static_cast<uint64_t>(pos); |
835 | 339 | } | 355 | } |
836 | @@ -358,7 +374,7 @@ | |||
837 | 358 | file_type = MEDIA_FILE_TYPE_VIDEO; | 374 | file_type = MEDIA_FILE_TYPE_VIDEO; |
838 | 359 | else if (is_audio_file(uri)) | 375 | else if (is_audio_file(uri)) |
839 | 360 | file_type = MEDIA_FILE_TYPE_AUDIO; | 376 | file_type = MEDIA_FILE_TYPE_AUDIO; |
841 | 361 | 377 | ||
842 | 362 | request_headers = headers; | 378 | request_headers = headers; |
843 | 363 | } | 379 | } |
844 | 364 | 380 | ||
845 | @@ -366,7 +382,7 @@ | |||
846 | 366 | { | 382 | { |
847 | 367 | if (source == NULL || request_headers.empty()) | 383 | if (source == NULL || request_headers.empty()) |
848 | 368 | return; | 384 | return; |
850 | 369 | 385 | ||
851 | 370 | if (request_headers.find("Cookie") != request_headers.end()) { | 386 | if (request_headers.find("Cookie") != request_headers.end()) { |
852 | 371 | if (g_object_class_find_property(G_OBJECT_GET_CLASS(source), | 387 | if (g_object_class_find_property(G_OBJECT_GET_CLASS(source), |
853 | 372 | "cookies") != NULL) { | 388 | "cookies") != NULL) { |
854 | @@ -375,7 +391,7 @@ | |||
855 | 375 | g_strfreev(cookies); | 391 | g_strfreev(cookies); |
856 | 376 | } | 392 | } |
857 | 377 | } | 393 | } |
859 | 378 | 394 | ||
860 | 379 | if (request_headers.find("User-Agent") != request_headers.end()) { | 395 | if (request_headers.find("User-Agent") != request_headers.end()) { |
861 | 380 | if (g_object_class_find_property(G_OBJECT_GET_CLASS(source), | 396 | if (g_object_class_find_property(G_OBJECT_GET_CLASS(source), |
862 | 381 | "user-agent") != NULL) { | 397 | "user-agent") != NULL) { |
863 | @@ -427,8 +443,9 @@ | |||
864 | 427 | } | 443 | } |
865 | 428 | 444 | ||
866 | 429 | // We only should query the pipeline if we actually succeeded in | 445 | // We only should query the pipeline if we actually succeeded in |
869 | 430 | // setting the requested state. | 446 | // setting the requested state. Also don't send on_video_dimensions_changed |
870 | 431 | if (result && new_state == GST_STATE_PLAYING) | 447 | // signal during EOS. |
871 | 448 | if (result && new_state == GST_STATE_PLAYING && !is_eos) | ||
872 | 432 | { | 449 | { |
873 | 433 | // Get the video height/width from the video sink | 450 | // Get the video height/width from the video sink |
874 | 434 | try | 451 | try |
875 | 435 | 452 | ||
876 | === modified file 'src/core/media/gstreamer/playbin.h' | |||
877 | --- src/core/media/gstreamer/playbin.h 2015-03-16 15:38:27 +0000 | |||
878 | +++ src/core/media/gstreamer/playbin.h 2015-03-16 15:38:27 +0000 | |||
879 | @@ -112,8 +112,10 @@ | |||
880 | 112 | GstElement* video_sink; | 112 | GstElement* video_sink; |
881 | 113 | core::Connection on_new_message_connection; | 113 | core::Connection on_new_message_connection; |
882 | 114 | bool is_seeking; | 114 | bool is_seeking; |
883 | 115 | mutable uint64_t previous_position; | ||
884 | 115 | core::ubuntu::media::Player::HeadersType request_headers; | 116 | core::ubuntu::media::Player::HeadersType request_headers; |
885 | 116 | core::ubuntu::media::Player::Lifetime player_lifetime; | 117 | core::ubuntu::media::Player::Lifetime player_lifetime; |
886 | 118 | bool is_eos; | ||
887 | 117 | struct | 119 | struct |
888 | 118 | { | 120 | { |
889 | 119 | core::Signal<void> about_to_finish; | 121 | core::Signal<void> about_to_finish; |
890 | 120 | 122 | ||
891 | === added file 'src/core/media/hashed_keyed_player_store.cpp' | |||
892 | --- src/core/media/hashed_keyed_player_store.cpp 1970-01-01 00:00:00 +0000 | |||
893 | +++ src/core/media/hashed_keyed_player_store.cpp 2015-03-16 15:38:27 +0000 | |||
894 | @@ -0,0 +1,80 @@ | |||
895 | 1 | /* | ||
896 | 2 | * Copyright © 2014 Canonical Ltd. | ||
897 | 3 | * | ||
898 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
899 | 5 | * under the terms of the GNU Lesser General Public License version 3, | ||
900 | 6 | * as published by the Free Software Foundation. | ||
901 | 7 | * | ||
902 | 8 | * This program is distributed in the hope that it will be useful, | ||
903 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
904 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
905 | 11 | * GNU Lesser General Public License for more details. | ||
906 | 12 | * | ||
907 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
908 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
909 | 15 | * | ||
910 | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> | ||
911 | 17 | */ | ||
912 | 18 | |||
913 | 19 | #include <core/media/hashed_keyed_player_store.h> | ||
914 | 20 | |||
915 | 21 | namespace media = core::ubuntu::media; | ||
916 | 22 | |||
917 | 23 | media::HashedKeyedPlayerStore::HashedKeyedPlayerStore() | ||
918 | 24 | { | ||
919 | 25 | } | ||
920 | 26 | |||
921 | 27 | const core::Property<std::shared_ptr<media::Player>>& media::HashedKeyedPlayerStore::current_player() const | ||
922 | 28 | { | ||
923 | 29 | return prop_current_player; | ||
924 | 30 | } | ||
925 | 31 | |||
926 | 32 | bool media::HashedKeyedPlayerStore::has_player_for_key(const media::Player::PlayerKey& key) const | ||
927 | 33 | { | ||
928 | 34 | std::lock_guard<std::mutex> lg{guard}; | ||
929 | 35 | return map.count(key) > 0; | ||
930 | 36 | } | ||
931 | 37 | |||
932 | 38 | std::shared_ptr<media::Player> media::HashedKeyedPlayerStore::player_for_key(const media::Player::PlayerKey& key) const | ||
933 | 39 | { | ||
934 | 40 | std::lock_guard<std::mutex> lg{guard}; | ||
935 | 41 | auto it = map.find(key); | ||
936 | 42 | |||
937 | 43 | if (it == map.end()) throw std::out_of_range | ||
938 | 44 | { | ||
939 | 45 | "HashedKeyedPlayerStore::player_for_key: No player known for " + std::to_string(key) | ||
940 | 46 | }; | ||
941 | 47 | |||
942 | 48 | return it->second; | ||
943 | 49 | } | ||
944 | 50 | |||
945 | 51 | void media::HashedKeyedPlayerStore::enumerate_players(const media::KeyedPlayerStore::PlayerEnumerator& enumerator) const | ||
946 | 52 | { | ||
947 | 53 | std::lock_guard<std::mutex> lg{guard}; | ||
948 | 54 | for (const auto& pair : map) | ||
949 | 55 | enumerator(pair.first, pair.second); | ||
950 | 56 | } | ||
951 | 57 | |||
952 | 58 | void media::HashedKeyedPlayerStore::add_player_for_key(const media::Player::PlayerKey& key, const std::shared_ptr<media::Player>& player) | ||
953 | 59 | { | ||
954 | 60 | std::lock_guard<std::mutex> lg{guard}; | ||
955 | 61 | map[key] = player; | ||
956 | 62 | } | ||
957 | 63 | |||
958 | 64 | void media::HashedKeyedPlayerStore::remove_player_for_key(const media::Player::PlayerKey& key) | ||
959 | 65 | { | ||
960 | 66 | std::lock_guard<std::mutex> lg{guard}; | ||
961 | 67 | auto it = map.find(key); | ||
962 | 68 | if (it != map.end()) | ||
963 | 69 | { | ||
964 | 70 | if (prop_current_player == it->second) | ||
965 | 71 | prop_current_player = nullptr; | ||
966 | 72 | |||
967 | 73 | map.erase(it); | ||
968 | 74 | } | ||
969 | 75 | } | ||
970 | 76 | |||
971 | 77 | void media::HashedKeyedPlayerStore::set_current_player_for_key(const media::Player::PlayerKey& key) | ||
972 | 78 | { | ||
973 | 79 | prop_current_player = player_for_key(key); | ||
974 | 80 | } | ||
975 | 0 | 81 | ||
976 | === added file 'src/core/media/hashed_keyed_player_store.h' | |||
977 | --- src/core/media/hashed_keyed_player_store.h 1970-01-01 00:00:00 +0000 | |||
978 | +++ src/core/media/hashed_keyed_player_store.h 2015-03-16 15:38:27 +0000 | |||
979 | @@ -0,0 +1,76 @@ | |||
980 | 1 | /* | ||
981 | 2 | * Copyright © 2014 Canonical Ltd. | ||
982 | 3 | * | ||
983 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
984 | 5 | * under the terms of the GNU Lesser General Public License version 3, | ||
985 | 6 | * as published by the Free Software Foundation. | ||
986 | 7 | * | ||
987 | 8 | * This program is distributed in the hope that it will be useful, | ||
988 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
989 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
990 | 11 | * GNU Lesser General Public License for more details. | ||
991 | 12 | * | ||
992 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
993 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
994 | 15 | * | ||
995 | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> | ||
996 | 17 | */ | ||
997 | 18 | |||
998 | 19 | #ifndef CORE_UBUNTU_MEDIA_HASHED_KEYED_PLAYER_STORE_H_ | ||
999 | 20 | #define CORE_UBUNTU_MEDIA_HASHED_KEYED_PLAYER_STORE_H_ | ||
1000 | 21 | |||
1001 | 22 | #include <core/media/keyed_player_store.h> | ||
1002 | 23 | |||
1003 | 24 | #include <mutex> | ||
1004 | 25 | #include <unordered_map> | ||
1005 | 26 | |||
1006 | 27 | namespace core | ||
1007 | 28 | { | ||
1008 | 29 | namespace ubuntu | ||
1009 | 30 | { | ||
1010 | 31 | namespace media | ||
1011 | 32 | { | ||
1012 | 33 | // Implements KeyedPlayerStore using a std::unordered_map. | ||
1013 | 34 | class HashedKeyedPlayerStore : public KeyedPlayerStore | ||
1014 | 35 | { | ||
1015 | 36 | public: | ||
1016 | 37 | HashedKeyedPlayerStore(); | ||
1017 | 38 | // We keep track of the "current" player, that is, the one | ||
1018 | 39 | // that has been created most recently, or has been explicitly foregrounded, or has been enabled for | ||
1019 | 40 | // background playback. We provide a getable/observable access to that designated instance. | ||
1020 | 41 | const core::Property<std::shared_ptr<media::Player>>& current_player() const override; | ||
1021 | 42 | |||
1022 | 43 | // We keep track of all known player sessions here and render them accessible via | ||
1023 | 44 | // the key. All of these functions are thread-safe but not reentrant. | ||
1024 | 45 | // Returns true iff a player is known for the given key. | ||
1025 | 46 | bool has_player_for_key(const Player::PlayerKey& key) const override; | ||
1026 | 47 | |||
1027 | 48 | // Returns the player for the given key or throws std::out_of_range if no player is known | ||
1028 | 49 | // for the given key. | ||
1029 | 50 | // Throws std::out_of_range if no player is known for the key. | ||
1030 | 51 | std::shared_ptr<Player> player_for_key(const Player::PlayerKey& key) const override; | ||
1031 | 52 | |||
1032 | 53 | // Enumerates all known players and invokes the given enumerator for each | ||
1033 | 54 | // (key, player) pair. | ||
1034 | 55 | void enumerate_players(const PlayerEnumerator& enumerator) const override; | ||
1035 | 56 | |||
1036 | 57 | // Adds the given player with the given key. | ||
1037 | 58 | void add_player_for_key(const Player::PlayerKey& key, const std::shared_ptr<Player>& player) override; | ||
1038 | 59 | |||
1039 | 60 | // Removes the player for the given key, and unsets it if it is the current one. | ||
1040 | 61 | void remove_player_for_key(const Player::PlayerKey& key) override; | ||
1041 | 62 | |||
1042 | 63 | // Makes the player known under the given key current. | ||
1043 | 64 | // Throws std::out_of_range if no player is known for the key. | ||
1044 | 65 | void set_current_player_for_key(const Player::PlayerKey& key) override; | ||
1045 | 66 | |||
1046 | 67 | private: | ||
1047 | 68 | core::Property<std::shared_ptr<Player>> prop_current_player; | ||
1048 | 69 | mutable std::mutex guard; | ||
1049 | 70 | std::unordered_map<Player::PlayerKey, std::shared_ptr<Player>> map; | ||
1050 | 71 | }; | ||
1051 | 72 | } | ||
1052 | 73 | } | ||
1053 | 74 | } | ||
1054 | 75 | |||
1055 | 76 | #endif // CORE_UBUNTU_MEDIA_KEYED_PLAYER_STORE_H_ | ||
1056 | 0 | 77 | ||
1057 | === added file 'src/core/media/keyed_player_store.cpp' | |||
1058 | === added file 'src/core/media/keyed_player_store.h' | |||
1059 | --- src/core/media/keyed_player_store.h 1970-01-01 00:00:00 +0000 | |||
1060 | +++ src/core/media/keyed_player_store.h 2015-03-16 15:38:27 +0000 | |||
1061 | @@ -0,0 +1,83 @@ | |||
1062 | 1 | /* | ||
1063 | 2 | * Copyright © 2014 Canonical Ltd. | ||
1064 | 3 | * | ||
1065 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
1066 | 5 | * under the terms of the GNU Lesser General Public License version 3, | ||
1067 | 6 | * as published by the Free Software Foundation. | ||
1068 | 7 | * | ||
1069 | 8 | * This program is distributed in the hope that it will be useful, | ||
1070 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1071 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1072 | 11 | * GNU Lesser General Public License for more details. | ||
1073 | 12 | * | ||
1074 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
1075 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1076 | 15 | * | ||
1077 | 16 | * Authored by: Thomas Voß <thomas.voss@canonical.com> | ||
1078 | 17 | */ | ||
1079 | 18 | |||
1080 | 19 | #ifndef CORE_UBUNTU_MEDIA_KEYED_PLAYER_STORE_H_ | ||
1081 | 20 | #define CORE_UBUNTU_MEDIA_KEYED_PLAYER_STORE_H_ | ||
1082 | 21 | |||
1083 | 22 | #include <core/media/player.h> | ||
1084 | 23 | |||
1085 | 24 | #include <core/property.h> | ||
1086 | 25 | |||
1087 | 26 | #include <functional> | ||
1088 | 27 | #include <memory> | ||
1089 | 28 | |||
1090 | 29 | namespace core | ||
1091 | 30 | { | ||
1092 | 31 | namespace ubuntu | ||
1093 | 32 | { | ||
1094 | 33 | namespace media | ||
1095 | 34 | { | ||
1096 | 35 | // An interface abstracting keyed lookups of known Player instances. | ||
1097 | 36 | class KeyedPlayerStore | ||
1098 | 37 | { | ||
1099 | 38 | public: | ||
1100 | 39 | // Save us some typing. | ||
1101 | 40 | typedef std::shared_ptr<KeyedPlayerStore> Ptr; | ||
1102 | 41 | // Functor for enumerating all known (key, player) pairs. | ||
1103 | 42 | typedef std::function | ||
1104 | 43 | < | ||
1105 | 44 | void( | ||
1106 | 45 | // The key of the player. | ||
1107 | 46 | const Player::PlayerKey&, | ||
1108 | 47 | // The actual player instance. | ||
1109 | 48 | const std::shared_ptr<Player>& | ||
1110 | 49 | ) | ||
1111 | 50 | > PlayerEnumerator; | ||
1112 | 51 | // We keep track of the "current" player, that is, the one | ||
1113 | 52 | // that has been created most recently and provide a getable/observable | ||
1114 | 53 | // access to that designated instance. | ||
1115 | 54 | virtual const core::Property<std::shared_ptr<Player>>& current_player() const = 0; | ||
1116 | 55 | |||
1117 | 56 | // We keep track of all known player sessions here and render them accessible via | ||
1118 | 57 | // the key. All of these functions are thread-safe but not reentrant. | ||
1119 | 58 | // Returns true iff a player is known for the given key. | ||
1120 | 59 | virtual bool has_player_for_key(const Player::PlayerKey& key) const = 0; | ||
1121 | 60 | // Returns the player for the given key or throws std::out_of_range if no player is known | ||
1122 | 61 | // for the given key. | ||
1123 | 62 | virtual std::shared_ptr<Player> player_for_key(const Player::PlayerKey& key) const = 0; | ||
1124 | 63 | // Enumerates all known players and invokes the given enumerator for each | ||
1125 | 64 | // (key, player) pair. | ||
1126 | 65 | virtual void enumerate_players(const PlayerEnumerator& enumerator) const = 0; | ||
1127 | 66 | // Adds the given player with the given key. | ||
1128 | 67 | virtual void add_player_for_key(const Player::PlayerKey& key, const std::shared_ptr<Player>& player) = 0; | ||
1129 | 68 | // Removes the player for the given key, and unsets it if it is the current one. | ||
1130 | 69 | virtual void remove_player_for_key(const Player::PlayerKey& key) = 0; | ||
1131 | 70 | // Makes the player known under the given key current. | ||
1132 | 71 | virtual void set_current_player_for_key(const Player::PlayerKey& key) = 0; | ||
1133 | 72 | |||
1134 | 73 | protected: | ||
1135 | 74 | KeyedPlayerStore() = default; | ||
1136 | 75 | KeyedPlayerStore(const KeyedPlayerStore&) = delete; | ||
1137 | 76 | virtual ~KeyedPlayerStore() = default; | ||
1138 | 77 | KeyedPlayerStore& operator=(const KeyedPlayerStore&) = delete; | ||
1139 | 78 | }; | ||
1140 | 79 | } | ||
1141 | 80 | } | ||
1142 | 81 | } | ||
1143 | 82 | |||
1144 | 83 | #endif // CORE_UBUNTU_MEDIA_KEYED_PLAYER_STORE_H_ | ||
1145 | 0 | 84 | ||
1146 | === modified file 'src/core/media/mpris/player.h' | |||
1147 | --- src/core/media/mpris/player.h 2015-03-16 15:38:27 +0000 | |||
1148 | +++ src/core/media/mpris/player.h 2015-03-16 15:38:27 +0000 | |||
1149 | @@ -136,6 +136,7 @@ | |||
1150 | 136 | struct Signals | 136 | struct Signals |
1151 | 137 | { | 137 | { |
1152 | 138 | DBUS_CPP_SIGNAL_DEF(Seeked, Player, std::int64_t) | 138 | DBUS_CPP_SIGNAL_DEF(Seeked, Player, std::int64_t) |
1153 | 139 | DBUS_CPP_SIGNAL_DEF(AboutToFinish, Player, void) | ||
1154 | 139 | DBUS_CPP_SIGNAL_DEF(EndOfStream, Player, void) | 140 | DBUS_CPP_SIGNAL_DEF(EndOfStream, Player, void) |
1155 | 140 | DBUS_CPP_SIGNAL_DEF(PlaybackStatusChanged, Player, core::ubuntu::media::Player::PlaybackStatus) | 141 | DBUS_CPP_SIGNAL_DEF(PlaybackStatusChanged, Player, core::ubuntu::media::Player::PlaybackStatus) |
1156 | 141 | DBUS_CPP_SIGNAL_DEF(VideoDimensionChanged, Player, core::ubuntu::media::video::Dimensions) | 142 | DBUS_CPP_SIGNAL_DEF(VideoDimensionChanged, Player, core::ubuntu::media::video::Dimensions) |
1157 | @@ -246,6 +247,7 @@ | |||
1158 | 246 | signals | 247 | signals |
1159 | 247 | { | 248 | { |
1160 | 248 | configuration.object->template get_signal<Signals::Seeked>(), | 249 | configuration.object->template get_signal<Signals::Seeked>(), |
1161 | 250 | configuration.object->template get_signal<Signals::AboutToFinish>(), | ||
1162 | 249 | configuration.object->template get_signal<Signals::EndOfStream>(), | 251 | configuration.object->template get_signal<Signals::EndOfStream>(), |
1163 | 250 | configuration.object->template get_signal<Signals::PlaybackStatusChanged>(), | 252 | configuration.object->template get_signal<Signals::PlaybackStatusChanged>(), |
1164 | 251 | configuration.object->template get_signal<Signals::VideoDimensionChanged>(), | 253 | configuration.object->template get_signal<Signals::VideoDimensionChanged>(), |
1165 | @@ -373,6 +375,7 @@ | |||
1166 | 373 | struct | 375 | struct |
1167 | 374 | { | 376 | { |
1168 | 375 | typename core::dbus::Signal<Signals::Seeked, Signals::Seeked::ArgumentType>::Ptr seeked_to; | 377 | typename core::dbus::Signal<Signals::Seeked, Signals::Seeked::ArgumentType>::Ptr seeked_to; |
1169 | 378 | typename core::dbus::Signal<Signals::AboutToFinish, Signals::AboutToFinish::ArgumentType>::Ptr about_to_finish; | ||
1170 | 376 | typename core::dbus::Signal<Signals::EndOfStream, Signals::EndOfStream::ArgumentType>::Ptr end_of_stream; | 379 | typename core::dbus::Signal<Signals::EndOfStream, Signals::EndOfStream::ArgumentType>::Ptr end_of_stream; |
1171 | 377 | typename core::dbus::Signal<Signals::PlaybackStatusChanged, Signals::PlaybackStatusChanged::ArgumentType>::Ptr playback_status_changed; | 380 | typename core::dbus::Signal<Signals::PlaybackStatusChanged, Signals::PlaybackStatusChanged::ArgumentType>::Ptr playback_status_changed; |
1172 | 378 | typename core::dbus::Signal<Signals::VideoDimensionChanged, Signals::VideoDimensionChanged::ArgumentType>::Ptr video_dimension_changed; | 381 | typename core::dbus::Signal<Signals::VideoDimensionChanged, Signals::VideoDimensionChanged::ArgumentType>::Ptr video_dimension_changed; |
1173 | 379 | 382 | ||
1174 | === added file 'src/core/media/null_track_list.h' | |||
1175 | --- src/core/media/null_track_list.h 1970-01-01 00:00:00 +0000 | |||
1176 | +++ src/core/media/null_track_list.h 2015-03-16 15:38:27 +0000 | |||
1177 | @@ -0,0 +1,114 @@ | |||
1178 | 1 | /* | ||
1179 | 2 | * | ||
1180 | 3 | * This program is free software: you can redistribute it and/or modify it | ||
1181 | 4 | * under the terms of the GNU Lesser General Public License version 3, | ||
1182 | 5 | * as published by the Free Software Foundation. | ||
1183 | 6 | * | ||
1184 | 7 | * This program is distributed in the hope that it will be useful, | ||
1185 | 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1186 | 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1187 | 10 | * GNU Lesser General Public License for more details. | ||
1188 | 11 | * | ||
1189 | 12 | * You should have received a copy of the GNU Lesser General Public License | ||
1190 | 13 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1191 | 14 | * | ||
1192 | 15 | * Authored by: Thomas Voß <thomas.voss@canonical.com> | ||
1193 | 16 | */ | ||
1194 | 17 | |||
1195 | 18 | #ifndef CORE_MEDIA_NULL_TRACK_LIST_H_ | ||
1196 | 19 | #define CORE_MEDIA_NULL_TRACK_LIST_H_ | ||
1197 | 20 | |||
1198 | 21 | #include <core/media/track.h> | ||
1199 | 22 | #include <core/media/track_list.h> | ||
1200 | 23 | |||
1201 | 24 | namespace core | ||
1202 | 25 | { | ||
1203 | 26 | namespace ubuntu | ||
1204 | 27 | { | ||
1205 | 28 | namespace media | ||
1206 | 29 | { | ||
1207 | 30 | // A helper type to replace the playlist implementation below. | ||
1208 | 31 | // Please note that this type is only a temporary manner. Ideally, | ||
1209 | 32 | // the actual implementation should be injected as a dependency from the | ||
1210 | 33 | // outside. | ||
1211 | 34 | struct NullTrackList : public media::TrackList | ||
1212 | 35 | { | ||
1213 | 36 | NullTrackList() = default; | ||
1214 | 37 | |||
1215 | 38 | bool has_next() | ||
1216 | 39 | { | ||
1217 | 40 | return false; | ||
1218 | 41 | } | ||
1219 | 42 | |||
1220 | 43 | media::Track::Id next() | ||
1221 | 44 | { | ||
1222 | 45 | return media::Track::Id{}; | ||
1223 | 46 | } | ||
1224 | 47 | |||
1225 | 48 | media::Track::UriType query_uri_for_track(const media::Track::Id&) | ||
1226 | 49 | { | ||
1227 | 50 | return media::Track::UriType{}; | ||
1228 | 51 | } | ||
1229 | 52 | |||
1230 | 53 | const core::Property<bool>& can_edit_tracks() const override | ||
1231 | 54 | { | ||
1232 | 55 | return props_and_sigs.can_edit_tracks; | ||
1233 | 56 | } | ||
1234 | 57 | |||
1235 | 58 | const core::Property<Container>& tracks() const override | ||
1236 | 59 | { | ||
1237 | 60 | return props_and_sigs.tracks; | ||
1238 | 61 | } | ||
1239 | 62 | |||
1240 | 63 | virtual media::Track::MetaData query_meta_data_for_track(const media::Track::Id&) override | ||
1241 | 64 | { | ||
1242 | 65 | return media::Track::MetaData{}; | ||
1243 | 66 | } | ||
1244 | 67 | |||
1245 | 68 | void add_track_with_uri_at(const media::Track::UriType&, const media::Track::Id&, bool) override | ||
1246 | 69 | { | ||
1247 | 70 | } | ||
1248 | 71 | |||
1249 | 72 | void remove_track(const media::Track::Id&) override | ||
1250 | 73 | { | ||
1251 | 74 | } | ||
1252 | 75 | |||
1253 | 76 | void go_to(const media::Track::Id&) override | ||
1254 | 77 | { | ||
1255 | 78 | } | ||
1256 | 79 | |||
1257 | 80 | const core::Signal<void>& on_track_list_replaced() const override | ||
1258 | 81 | { | ||
1259 | 82 | return props_and_sigs.on_track_list_replaced; | ||
1260 | 83 | } | ||
1261 | 84 | |||
1262 | 85 | const core::Signal<media::Track::Id>& on_track_added() const override | ||
1263 | 86 | { | ||
1264 | 87 | return props_and_sigs.on_track_added; | ||
1265 | 88 | } | ||
1266 | 89 | |||
1267 | 90 | const core::Signal<media::Track::Id>& on_track_removed() const override | ||
1268 | 91 | { | ||
1269 | 92 | return props_and_sigs.on_track_removed; | ||
1270 | 93 | } | ||
1271 | 94 | |||
1272 | 95 | const core::Signal<media::Track::Id>& on_track_changed() const override | ||
1273 | 96 | { | ||
1274 | 97 | return props_and_sigs.on_track_changed; | ||
1275 | 98 | } | ||
1276 | 99 | |||
1277 | 100 | struct | ||
1278 | 101 | { | ||
1279 | 102 | core::Property<bool> can_edit_tracks; | ||
1280 | 103 | core::Property<TrackList::Container> tracks; | ||
1281 | 104 | core::Signal<void> on_track_list_replaced; | ||
1282 | 105 | core::Signal<media::Track::Id> on_track_added; | ||
1283 | 106 | core::Signal<media::Track::Id> on_track_removed; | ||
1284 | 107 | core::Signal<media::Track::Id> on_track_changed; | ||
1285 | 108 | } props_and_sigs; | ||
1286 | 109 | }; | ||
1287 | 110 | } | ||
1288 | 111 | } | ||
1289 | 112 | } | ||
1290 | 113 | |||
1291 | 114 | #endif // CORE_MEDIA_NULL_TRACK_LIST_H_ | ||
1292 | 0 | 115 | ||
1293 | === modified file 'src/core/media/player.cpp' | |||
1294 | --- src/core/media/player.cpp 2015-03-16 15:38:27 +0000 | |||
1295 | +++ src/core/media/player.cpp 2015-03-16 15:38:27 +0000 | |||
1296 | @@ -31,7 +31,6 @@ | |||
1297 | 31 | { | 31 | { |
1298 | 32 | static const media::Player::Configuration config | 32 | static const media::Player::Configuration config |
1299 | 33 | { | 33 | { |
1300 | 34 | std::string{""}, | ||
1301 | 35 | 0, | 34 | 0, |
1302 | 36 | nullptr, | 35 | nullptr, |
1303 | 37 | nullptr | 36 | nullptr |
1304 | 38 | 37 | ||
1305 | === modified file 'src/core/media/player_configuration.h' | |||
1306 | --- src/core/media/player_configuration.h 2014-09-09 10:28:32 +0000 | |||
1307 | +++ src/core/media/player_configuration.h 2015-03-16 15:38:27 +0000 | |||
1308 | @@ -27,9 +27,6 @@ | |||
1309 | 27 | // to the implementation in a way that is opaque to the client. | 27 | // to the implementation in a way that is opaque to the client. |
1310 | 28 | struct core::ubuntu::media::Player::Configuration | 28 | struct core::ubuntu::media::Player::Configuration |
1311 | 29 | { | 29 | { |
1312 | 30 | // An identifier that is helpful in referencing the player instance | ||
1313 | 31 | // across multiple services. | ||
1314 | 32 | std::string identity; | ||
1315 | 33 | // Unique key for identifying the session. | 30 | // Unique key for identifying the session. |
1316 | 34 | core::ubuntu::media::Player::PlayerKey key; | 31 | core::ubuntu::media::Player::PlayerKey key; |
1317 | 35 | // The bus connection to expose objects on. | 32 | // The bus connection to expose objects on. |
1318 | 36 | 33 | ||
1319 | === modified file 'src/core/media/player_implementation.cpp' | |||
1320 | --- src/core/media/player_implementation.cpp 2015-03-16 15:38:27 +0000 | |||
1321 | +++ src/core/media/player_implementation.cpp 2015-03-16 15:38:27 +0000 | |||
1322 | @@ -23,6 +23,7 @@ | |||
1323 | 23 | 23 | ||
1324 | 24 | #include "client_death_observer.h" | 24 | #include "client_death_observer.h" |
1325 | 25 | #include "engine.h" | 25 | #include "engine.h" |
1326 | 26 | #include "null_track_list.h" | ||
1327 | 26 | #include "track_list_implementation.h" | 27 | #include "track_list_implementation.h" |
1328 | 27 | 28 | ||
1329 | 28 | #include "gstreamer/engine.h" | 29 | #include "gstreamer/engine.h" |
1330 | @@ -39,7 +40,8 @@ | |||
1331 | 39 | 40 | ||
1332 | 40 | using namespace std; | 41 | using namespace std; |
1333 | 41 | 42 | ||
1335 | 42 | struct media::PlayerImplementation::Private : | 43 | template<typename Parent> |
1336 | 44 | struct media::PlayerImplementation<Parent>::Private : | ||
1337 | 43 | public std::enable_shared_from_this<Private> | 45 | public std::enable_shared_from_this<Private> |
1338 | 44 | { | 46 | { |
1339 | 45 | enum class wakelock_clear_t | 47 | enum class wakelock_clear_t |
1340 | @@ -50,30 +52,18 @@ | |||
1341 | 50 | WAKELOCK_CLEAR_INVALID | 52 | WAKELOCK_CLEAR_INVALID |
1342 | 51 | }; | 53 | }; |
1343 | 52 | 54 | ||
1345 | 53 | Private(PlayerImplementation* parent, const media::PlayerImplementation::Configuration& config) | 55 | Private(PlayerImplementation* parent, const media::PlayerImplementation<Parent>::Configuration& config) |
1346 | 54 | : parent(parent), | 56 | : parent(parent), |
1347 | 55 | config(config), | 57 | config(config), |
1348 | 56 | display_state_lock(config.power_state_controller->display_state_lock()), | 58 | display_state_lock(config.power_state_controller->display_state_lock()), |
1349 | 57 | system_state_lock(config.power_state_controller->system_state_lock()), | 59 | system_state_lock(config.power_state_controller->system_state_lock()), |
1350 | 58 | engine(std::make_shared<gstreamer::Engine>()), | 60 | engine(std::make_shared<gstreamer::Engine>()), |
1355 | 59 | track_list( | 61 | track_list(std::make_shared<NullTrackList>()), |
1352 | 60 | new media::TrackListImplementation( | ||
1353 | 61 | config.session->path().as_string() + "/TrackList", | ||
1354 | 62 | engine->meta_data_extractor())), | ||
1356 | 63 | system_wakelock_count(0), | 62 | system_wakelock_count(0), |
1357 | 64 | display_wakelock_count(0), | 63 | display_wakelock_count(0), |
1358 | 65 | previous_state(Engine::State::stopped), | 64 | previous_state(Engine::State::stopped), |
1359 | 66 | engine_state_change_connection(engine->state().changed().connect(make_state_change_handler())) | 65 | engine_state_change_connection(engine->state().changed().connect(make_state_change_handler())) |
1360 | 67 | { | 66 | { |
1361 | 68 | config.client_death_observer->register_for_death_notifications_with_key(config.key); | ||
1362 | 69 | config.client_death_observer->on_client_with_key_died().connect([this](const media::Player::PlayerKey& died) | ||
1363 | 70 | { | ||
1364 | 71 | if (died != this->config.key) | ||
1365 | 72 | return; | ||
1366 | 73 | |||
1367 | 74 | on_client_died(); | ||
1368 | 75 | }); | ||
1369 | 76 | |||
1370 | 77 | // Poor man's logging of release/acquire events. | 67 | // Poor man's logging of release/acquire events. |
1371 | 78 | display_state_lock->acquired().connect([](media::power::DisplayState state) | 68 | display_state_lock->acquired().connect([](media::power::DisplayState state) |
1372 | 79 | { | 69 | { |
1373 | @@ -207,7 +197,7 @@ | |||
1374 | 207 | if (--system_wakelock_count == 0) | 197 | if (--system_wakelock_count == 0) |
1375 | 208 | { | 198 | { |
1376 | 209 | std::cout << "Clearing system wakelock." << std::endl; | 199 | std::cout << "Clearing system wakelock." << std::endl; |
1378 | 210 | system_state_lock->request_release(media::power::SystemState::active); | 200 | system_state_lock->request_release(media::power::SystemState::active); |
1379 | 211 | } | 201 | } |
1380 | 212 | break; | 202 | break; |
1381 | 213 | case wakelock_clear_t::WAKELOCK_CLEAR_DISPLAY: | 203 | case wakelock_clear_t::WAKELOCK_CLEAR_DISPLAY: |
1382 | @@ -257,7 +247,7 @@ | |||
1383 | 257 | // the execution of the functor may surpass the lifetime of this Private | 247 | // the execution of the functor may surpass the lifetime of this Private |
1384 | 258 | // object instance. By keeping a weak_ptr to the private object instance | 248 | // object instance. By keeping a weak_ptr to the private object instance |
1385 | 259 | // we can check if the object is dead before calling methods on it | 249 | // we can check if the object is dead before calling methods on it |
1387 | 260 | std::weak_ptr<Private> weak_self{shared_from_this()}; | 250 | std::weak_ptr<Private> weak_self{this->shared_from_this()}; |
1388 | 261 | auto wakelock_type = current_wakelock_type(); | 251 | auto wakelock_type = current_wakelock_type(); |
1389 | 262 | return [weak_self, wakelock_type] { | 252 | return [weak_self, wakelock_type] { |
1390 | 263 | if (auto self = weak_self.lock()) | 253 | if (auto self = weak_self.lock()) |
1391 | @@ -271,14 +261,14 @@ | |||
1392 | 271 | } | 261 | } |
1393 | 272 | 262 | ||
1394 | 273 | // Our link back to our parent. | 263 | // Our link back to our parent. |
1396 | 274 | media::PlayerImplementation* parent; | 264 | media::PlayerImplementation<Parent>* parent; |
1397 | 275 | // We just store the parameters passed on construction. | 265 | // We just store the parameters passed on construction. |
1399 | 276 | media::PlayerImplementation::Configuration config; | 266 | media::PlayerImplementation<Parent>::Configuration config; |
1400 | 277 | media::power::StateController::Lock<media::power::DisplayState>::Ptr display_state_lock; | 267 | media::power::StateController::Lock<media::power::DisplayState>::Ptr display_state_lock; |
1401 | 278 | media::power::StateController::Lock<media::power::SystemState>::Ptr system_state_lock; | 268 | media::power::StateController::Lock<media::power::SystemState>::Ptr system_state_lock; |
1402 | 279 | 269 | ||
1403 | 280 | std::shared_ptr<Engine> engine; | 270 | std::shared_ptr<Engine> engine; |
1405 | 281 | std::shared_ptr<TrackListImplementation> track_list; | 271 | std::shared_ptr<media::NullTrackList> track_list; |
1406 | 282 | std::atomic<int> system_wakelock_count; | 272 | std::atomic<int> system_wakelock_count; |
1407 | 283 | std::atomic<int> display_wakelock_count; | 273 | std::atomic<int> display_wakelock_count; |
1408 | 284 | Engine::State previous_state; | 274 | Engine::State previous_state; |
1409 | @@ -286,36 +276,29 @@ | |||
1410 | 286 | core::Connection engine_state_change_connection; | 276 | core::Connection engine_state_change_connection; |
1411 | 287 | }; | 277 | }; |
1412 | 288 | 278 | ||
1423 | 289 | media::PlayerImplementation::PlayerImplementation(const media::PlayerImplementation::Configuration& config) | 279 | template<typename Parent> |
1424 | 290 | : media::PlayerSkeleton | 280 | media::PlayerImplementation<Parent>::PlayerImplementation(const media::PlayerImplementation<Parent>::Configuration& config) |
1425 | 291 | { | 281 | : Parent{config.parent}, |
1416 | 292 | media::PlayerSkeleton::Configuration | ||
1417 | 293 | { | ||
1418 | 294 | config.bus, | ||
1419 | 295 | config.session, | ||
1420 | 296 | config.identity | ||
1421 | 297 | } | ||
1422 | 298 | }, | ||
1426 | 299 | d{std::make_shared<Private>(this, config)} | 282 | d{std::make_shared<Private>(this, config)} |
1427 | 300 | { | 283 | { |
1428 | 301 | // Initialize default values for Player interface properties | 284 | // Initialize default values for Player interface properties |
1443 | 302 | can_play().set(true); | 285 | Parent::can_play().set(true); |
1444 | 303 | can_pause().set(true); | 286 | Parent::can_pause().set(true); |
1445 | 304 | can_seek().set(true); | 287 | Parent::can_seek().set(true); |
1446 | 305 | can_go_previous().set(true); | 288 | Parent::can_go_previous().set(true); |
1447 | 306 | can_go_next().set(true); | 289 | Parent::can_go_next().set(true); |
1448 | 307 | is_video_source().set(false); | 290 | Parent::is_video_source().set(false); |
1449 | 308 | is_audio_source().set(false); | 291 | Parent::is_audio_source().set(false); |
1450 | 309 | is_shuffle().set(true); | 292 | Parent::is_shuffle().set(true); |
1451 | 310 | playback_rate().set(1.f); | 293 | Parent::playback_rate().set(1.f); |
1452 | 311 | playback_status().set(Player::PlaybackStatus::null); | 294 | Parent::playback_status().set(Player::PlaybackStatus::null); |
1453 | 312 | loop_status().set(Player::LoopStatus::none); | 295 | Parent::loop_status().set(Player::LoopStatus::none); |
1454 | 313 | position().set(0); | 296 | Parent::position().set(0); |
1455 | 314 | duration().set(0); | 297 | Parent::duration().set(0); |
1456 | 315 | audio_stream_role().set(Player::AudioStreamRole::multimedia); | 298 | Parent::audio_stream_role().set(Player::AudioStreamRole::multimedia); |
1457 | 316 | d->engine->audio_stream_role().set(Player::AudioStreamRole::multimedia); | 299 | d->engine->audio_stream_role().set(Player::AudioStreamRole::multimedia); |
1460 | 317 | orientation().set(Player::Orientation::rotate0); | 300 | Parent::orientation().set(Player::Orientation::rotate0); |
1461 | 318 | lifetime().set(Player::Lifetime::normal); | 301 | Parent::lifetime().set(Player::Lifetime::normal); |
1462 | 319 | d->engine->lifetime().set(Player::Lifetime::normal); | 302 | d->engine->lifetime().set(Player::Lifetime::normal); |
1463 | 320 | 303 | ||
1464 | 321 | // Make sure that the Position property gets updated from the Engine | 304 | // Make sure that the Position property gets updated from the Engine |
1465 | @@ -324,7 +307,7 @@ | |||
1466 | 324 | { | 307 | { |
1467 | 325 | return d->engine->position().get(); | 308 | return d->engine->position().get(); |
1468 | 326 | }; | 309 | }; |
1470 | 327 | position().install(position_getter); | 310 | Parent::position().install(position_getter); |
1471 | 328 | 311 | ||
1472 | 329 | // Make sure that the Duration property gets updated from the Engine | 312 | // Make sure that the Duration property gets updated from the Engine |
1473 | 330 | // every time the client requests duration | 313 | // every time the client requests duration |
1474 | @@ -332,23 +315,23 @@ | |||
1475 | 332 | { | 315 | { |
1476 | 333 | return d->engine->duration().get(); | 316 | return d->engine->duration().get(); |
1477 | 334 | }; | 317 | }; |
1479 | 335 | duration().install(duration_getter); | 318 | Parent::duration().install(duration_getter); |
1480 | 336 | 319 | ||
1481 | 337 | std::function<bool()> video_type_getter = [this]() | 320 | std::function<bool()> video_type_getter = [this]() |
1482 | 338 | { | 321 | { |
1483 | 339 | return d->engine->is_video_source().get(); | 322 | return d->engine->is_video_source().get(); |
1484 | 340 | }; | 323 | }; |
1486 | 341 | is_video_source().install(video_type_getter); | 324 | Parent::is_video_source().install(video_type_getter); |
1487 | 342 | 325 | ||
1488 | 343 | std::function<bool()> audio_type_getter = [this]() | 326 | std::function<bool()> audio_type_getter = [this]() |
1489 | 344 | { | 327 | { |
1490 | 345 | return d->engine->is_audio_source().get(); | 328 | return d->engine->is_audio_source().get(); |
1491 | 346 | }; | 329 | }; |
1493 | 347 | is_audio_source().install(audio_type_getter); | 330 | Parent::is_audio_source().install(audio_type_getter); |
1494 | 348 | 331 | ||
1495 | 349 | // Make sure that the audio_stream_role property gets updated on the Engine side | 332 | // Make sure that the audio_stream_role property gets updated on the Engine side |
1496 | 350 | // whenever the client side sets the role | 333 | // whenever the client side sets the role |
1498 | 351 | audio_stream_role().changed().connect([this](media::Player::AudioStreamRole new_role) | 334 | Parent::audio_stream_role().changed().connect([this](media::Player::AudioStreamRole new_role) |
1499 | 352 | { | 335 | { |
1500 | 353 | d->engine->audio_stream_role().set(new_role); | 336 | d->engine->audio_stream_role().set(new_role); |
1501 | 354 | }); | 337 | }); |
1502 | @@ -357,16 +340,18 @@ | |||
1503 | 357 | // update the Player's cached value | 340 | // update the Player's cached value |
1504 | 358 | d->engine->orientation().changed().connect([this](const Player::Orientation& o) | 341 | d->engine->orientation().changed().connect([this](const Player::Orientation& o) |
1505 | 359 | { | 342 | { |
1507 | 360 | orientation().set(o); | 343 | Parent::orientation().set(o); |
1508 | 361 | }); | 344 | }); |
1509 | 362 | 345 | ||
1511 | 363 | lifetime().changed().connect([this](media::Player::Lifetime lifetime) | 346 | Parent::lifetime().changed().connect([this](media::Player::Lifetime lifetime) |
1512 | 364 | { | 347 | { |
1513 | 365 | d->engine->lifetime().set(lifetime); | 348 | d->engine->lifetime().set(lifetime); |
1514 | 366 | }); | 349 | }); |
1515 | 367 | 350 | ||
1516 | 368 | d->engine->about_to_finish_signal().connect([this]() | 351 | d->engine->about_to_finish_signal().connect([this]() |
1517 | 369 | { | 352 | { |
1518 | 353 | Parent::about_to_finish()(); | ||
1519 | 354 | |||
1520 | 370 | if (d->track_list->has_next()) | 355 | if (d->track_list->has_next()) |
1521 | 371 | { | 356 | { |
1522 | 372 | Track::UriType uri = d->track_list->query_uri_for_track(d->track_list->next()); | 357 | Track::UriType uri = d->track_list->query_uri_for_track(d->track_list->next()); |
1523 | @@ -386,31 +371,52 @@ | |||
1524 | 386 | 371 | ||
1525 | 387 | d->engine->seeked_to_signal().connect([this](uint64_t value) | 372 | d->engine->seeked_to_signal().connect([this](uint64_t value) |
1526 | 388 | { | 373 | { |
1528 | 389 | seeked_to()(value); | 374 | Parent::seeked_to()(value); |
1529 | 390 | }); | 375 | }); |
1530 | 391 | 376 | ||
1531 | 392 | d->engine->end_of_stream_signal().connect([this]() | 377 | d->engine->end_of_stream_signal().connect([this]() |
1532 | 393 | { | 378 | { |
1534 | 394 | end_of_stream()(); | 379 | Parent::end_of_stream()(); |
1535 | 395 | }); | 380 | }); |
1536 | 396 | 381 | ||
1537 | 397 | d->engine->playback_status_changed_signal().connect([this](const Player::PlaybackStatus& status) | 382 | d->engine->playback_status_changed_signal().connect([this](const Player::PlaybackStatus& status) |
1538 | 398 | { | 383 | { |
1540 | 399 | playback_status_changed()(status); | 384 | Parent::playback_status_changed()(status); |
1541 | 400 | }); | 385 | }); |
1542 | 401 | 386 | ||
1543 | 402 | d->engine->video_dimension_changed_signal().connect([this](const media::video::Dimensions& dimensions) | 387 | d->engine->video_dimension_changed_signal().connect([this](const media::video::Dimensions& dimensions) |
1544 | 403 | { | 388 | { |
1546 | 404 | video_dimension_changed()(dimensions); | 389 | Parent::video_dimension_changed()(dimensions); |
1547 | 405 | }); | 390 | }); |
1548 | 406 | 391 | ||
1549 | 407 | d->engine->error_signal().connect([this](const Player::Error& e) | 392 | d->engine->error_signal().connect([this](const Player::Error& e) |
1550 | 408 | { | 393 | { |
1552 | 409 | error()(e); | 394 | Parent::error()(e); |
1553 | 395 | }); | ||
1554 | 396 | |||
1555 | 397 | // Everything is setup, we now subscribe to death notifications. | ||
1556 | 398 | std::weak_ptr<Private> wp{d}; | ||
1557 | 399 | |||
1558 | 400 | d->config.client_death_observer->register_for_death_notifications_with_key(config.key); | ||
1559 | 401 | d->config.client_death_observer->on_client_with_key_died().connect([wp](const media::Player::PlayerKey& died) | ||
1560 | 402 | { | ||
1561 | 403 | if (auto sp = wp.lock()) | ||
1562 | 404 | { | ||
1563 | 405 | if (died != sp->config.key) | ||
1564 | 406 | return; | ||
1565 | 407 | |||
1566 | 408 | static const std::chrono::milliseconds timeout{1000}; | ||
1567 | 409 | media::timeout(timeout.count(), true, [wp]() | ||
1568 | 410 | { | ||
1569 | 411 | if (auto sp = wp.lock()) | ||
1570 | 412 | sp->on_client_died(); | ||
1571 | 413 | }); | ||
1572 | 414 | } | ||
1573 | 410 | }); | 415 | }); |
1574 | 411 | } | 416 | } |
1575 | 412 | 417 | ||
1577 | 413 | media::PlayerImplementation::~PlayerImplementation() | 418 | template<typename Parent> |
1578 | 419 | media::PlayerImplementation<Parent>::~PlayerImplementation() | ||
1579 | 414 | { | 420 | { |
1580 | 415 | // Install null getters as these properties may be destroyed | 421 | // Install null getters as these properties may be destroyed |
1581 | 416 | // after the engine has been destroyed since they are owned by the | 422 | // after the engine has been destroyed since they are owned by the |
1582 | @@ -419,84 +425,101 @@ | |||
1583 | 419 | { | 425 | { |
1584 | 420 | return static_cast<uint64_t>(0); | 426 | return static_cast<uint64_t>(0); |
1585 | 421 | }; | 427 | }; |
1587 | 422 | position().install(position_getter); | 428 | Parent::position().install(position_getter); |
1588 | 423 | 429 | ||
1589 | 424 | std::function<uint64_t()> duration_getter = [this]() | 430 | std::function<uint64_t()> duration_getter = [this]() |
1590 | 425 | { | 431 | { |
1591 | 426 | return static_cast<uint64_t>(0); | 432 | return static_cast<uint64_t>(0); |
1592 | 427 | }; | 433 | }; |
1594 | 428 | duration().install(duration_getter); | 434 | Parent::duration().install(duration_getter); |
1595 | 429 | 435 | ||
1596 | 430 | std::function<bool()> video_type_getter = [this]() | 436 | std::function<bool()> video_type_getter = [this]() |
1597 | 431 | { | 437 | { |
1598 | 432 | return false; | 438 | return false; |
1599 | 433 | }; | 439 | }; |
1601 | 434 | is_video_source().install(video_type_getter); | 440 | Parent::is_video_source().install(video_type_getter); |
1602 | 435 | 441 | ||
1603 | 436 | std::function<bool()> audio_type_getter = [this]() | 442 | std::function<bool()> audio_type_getter = [this]() |
1604 | 437 | { | 443 | { |
1605 | 438 | return false; | 444 | return false; |
1606 | 439 | }; | 445 | }; |
1608 | 440 | is_audio_source().install(audio_type_getter); | 446 | Parent::is_audio_source().install(audio_type_getter); |
1609 | 441 | } | 447 | } |
1610 | 442 | 448 | ||
1612 | 443 | std::shared_ptr<media::TrackList> media::PlayerImplementation::track_list() | 449 | template<typename Parent> |
1613 | 450 | std::shared_ptr<media::TrackList> media::PlayerImplementation<Parent>::track_list() | ||
1614 | 444 | { | 451 | { |
1615 | 445 | return d->track_list; | 452 | return d->track_list; |
1616 | 446 | } | 453 | } |
1617 | 447 | 454 | ||
1618 | 448 | // TODO: Convert this to be a property instead of sync call | 455 | // TODO: Convert this to be a property instead of sync call |
1620 | 449 | media::Player::PlayerKey media::PlayerImplementation::key() const | 456 | template<typename Parent> |
1621 | 457 | media::Player::PlayerKey media::PlayerImplementation<Parent>::key() const | ||
1622 | 450 | { | 458 | { |
1623 | 451 | return d->config.key; | 459 | return d->config.key; |
1624 | 452 | } | 460 | } |
1625 | 453 | 461 | ||
1627 | 454 | media::video::Sink::Ptr media::PlayerImplementation::create_gl_texture_video_sink(std::uint32_t texture_id) | 462 | template<typename Parent> |
1628 | 463 | media::video::Sink::Ptr media::PlayerImplementation<Parent>::create_gl_texture_video_sink(std::uint32_t texture_id) | ||
1629 | 455 | { | 464 | { |
1630 | 456 | d->engine->create_video_sink(texture_id); | 465 | d->engine->create_video_sink(texture_id); |
1631 | 457 | return media::video::Sink::Ptr{}; | 466 | return media::video::Sink::Ptr{}; |
1632 | 458 | } | 467 | } |
1633 | 459 | 468 | ||
1635 | 460 | bool media::PlayerImplementation::open_uri(const Track::UriType& uri) | 469 | template<typename Parent> |
1636 | 470 | bool media::PlayerImplementation<Parent>::open_uri(const Track::UriType& uri) | ||
1637 | 461 | { | 471 | { |
1638 | 462 | return d->engine->open_resource_for_uri(uri); | 472 | return d->engine->open_resource_for_uri(uri); |
1639 | 463 | } | 473 | } |
1640 | 464 | 474 | ||
1642 | 465 | bool media::PlayerImplementation::open_uri(const Track::UriType& uri, const Player::HeadersType& headers) | 475 | template<typename Parent> |
1643 | 476 | bool media::PlayerImplementation<Parent>::open_uri(const Track::UriType& uri, const Player::HeadersType& headers) | ||
1644 | 466 | { | 477 | { |
1645 | 467 | return d->engine->open_resource_for_uri(uri, headers); | 478 | return d->engine->open_resource_for_uri(uri, headers); |
1646 | 468 | } | 479 | } |
1647 | 469 | 480 | ||
1657 | 470 | void media::PlayerImplementation::next() | 481 | template<typename Parent> |
1658 | 471 | { | 482 | void media::PlayerImplementation<Parent>::next() |
1659 | 472 | } | 483 | { |
1660 | 473 | 484 | } | |
1661 | 474 | void media::PlayerImplementation::previous() | 485 | |
1662 | 475 | { | 486 | template<typename Parent> |
1663 | 476 | } | 487 | void media::PlayerImplementation<Parent>::previous() |
1664 | 477 | 488 | { | |
1665 | 478 | void media::PlayerImplementation::play() | 489 | } |
1666 | 490 | |||
1667 | 491 | template<typename Parent> | ||
1668 | 492 | void media::PlayerImplementation<Parent>::play() | ||
1669 | 479 | { | 493 | { |
1670 | 480 | d->engine->play(); | 494 | d->engine->play(); |
1671 | 481 | } | 495 | } |
1672 | 482 | 496 | ||
1674 | 483 | void media::PlayerImplementation::pause() | 497 | template<typename Parent> |
1675 | 498 | void media::PlayerImplementation<Parent>::pause() | ||
1676 | 484 | { | 499 | { |
1677 | 485 | d->engine->pause(); | 500 | d->engine->pause(); |
1678 | 486 | } | 501 | } |
1679 | 487 | 502 | ||
1681 | 488 | void media::PlayerImplementation::stop() | 503 | template<typename Parent> |
1682 | 504 | void media::PlayerImplementation<Parent>::stop() | ||
1683 | 489 | { | 505 | { |
1684 | 490 | std::cout << __PRETTY_FUNCTION__ << std::endl; | 506 | std::cout << __PRETTY_FUNCTION__ << std::endl; |
1685 | 491 | d->engine->stop(); | 507 | d->engine->stop(); |
1686 | 492 | } | 508 | } |
1687 | 493 | 509 | ||
1689 | 494 | void media::PlayerImplementation::seek_to(const std::chrono::microseconds& ms) | 510 | template<typename Parent> |
1690 | 511 | void media::PlayerImplementation<Parent>::seek_to(const std::chrono::microseconds& ms) | ||
1691 | 495 | { | 512 | { |
1692 | 496 | d->engine->seek_to(ms); | 513 | d->engine->seek_to(ms); |
1693 | 497 | } | 514 | } |
1694 | 498 | 515 | ||
1696 | 499 | const core::Signal<>& media::PlayerImplementation::on_client_disconnected() const | 516 | template<typename Parent> |
1697 | 517 | const core::Signal<>& media::PlayerImplementation<Parent>::on_client_disconnected() const | ||
1698 | 500 | { | 518 | { |
1699 | 501 | return d->on_client_disconnected; | 519 | return d->on_client_disconnected; |
1700 | 502 | } | 520 | } |
1701 | 521 | |||
1702 | 522 | #include <core/media/player_skeleton.h> | ||
1703 | 523 | |||
1704 | 524 | // For linking purposes, we have to make sure that we have all symbols included within the dso. | ||
1705 | 525 | template class media::PlayerImplementation<media::PlayerSkeleton>; | ||
1706 | 503 | 526 | ||
1707 | === modified file 'src/core/media/player_implementation.h' | |||
1708 | --- src/core/media/player_implementation.h 2015-03-16 15:38:27 +0000 | |||
1709 | +++ src/core/media/player_implementation.h 2015-03-16 15:38:27 +0000 | |||
1710 | @@ -19,8 +19,9 @@ | |||
1711 | 19 | #ifndef CORE_UBUNTU_MEDIA_PLAYER_IMPLEMENTATION_H_ | 19 | #ifndef CORE_UBUNTU_MEDIA_PLAYER_IMPLEMENTATION_H_ |
1712 | 20 | #define CORE_UBUNTU_MEDIA_PLAYER_IMPLEMENTATION_H_ | 20 | #define CORE_UBUNTU_MEDIA_PLAYER_IMPLEMENTATION_H_ |
1713 | 21 | 21 | ||
1715 | 22 | #include "player_skeleton.h" | 22 | #include <core/media/player.h> |
1716 | 23 | 23 | ||
1717 | 24 | #include "apparmor/ubuntu.h" | ||
1718 | 24 | #include "client_death_observer.h" | 25 | #include "client_death_observer.h" |
1719 | 25 | #include "power/state_controller.h" | 26 | #include "power/state_controller.h" |
1720 | 26 | 27 | ||
1721 | @@ -35,18 +36,17 @@ | |||
1722 | 35 | class Engine; | 36 | class Engine; |
1723 | 36 | class Service; | 37 | class Service; |
1724 | 37 | 38 | ||
1726 | 38 | class PlayerImplementation : public PlayerSkeleton | 39 | template<typename Parent> |
1727 | 40 | class PlayerImplementation : public Parent | ||
1728 | 39 | { | 41 | { |
1729 | 40 | public: | 42 | public: |
1730 | 41 | // All creation time arguments go here | 43 | // All creation time arguments go here |
1731 | 42 | struct Configuration | 44 | struct Configuration |
1732 | 43 | { | 45 | { |
1739 | 44 | std::string identity; | 46 | // All creation time configuration options of the Parent class. |
1740 | 45 | std::shared_ptr<core::dbus::Bus> bus; | 47 | typename Parent::Configuration parent; |
1741 | 46 | std::shared_ptr<core::dbus::Object> session; | 48 | // The unique key identifying the player instance. |
1742 | 47 | std::shared_ptr<Service> service; | 49 | Player::PlayerKey key; |
1737 | 48 | PlayerKey key; | ||
1738 | 49 | |||
1743 | 50 | // Functional dependencies | 50 | // Functional dependencies |
1744 | 51 | ClientDeathObserver::Ptr client_death_observer; | 51 | ClientDeathObserver::Ptr client_death_observer; |
1745 | 52 | power::StateController::Ptr power_state_controller; | 52 | power::StateController::Ptr power_state_controller; |
1746 | @@ -56,7 +56,7 @@ | |||
1747 | 56 | ~PlayerImplementation(); | 56 | ~PlayerImplementation(); |
1748 | 57 | 57 | ||
1749 | 58 | virtual std::shared_ptr<TrackList> track_list(); | 58 | virtual std::shared_ptr<TrackList> track_list(); |
1751 | 59 | virtual PlayerKey key() const; | 59 | virtual Player::PlayerKey key() const; |
1752 | 60 | 60 | ||
1753 | 61 | virtual video::Sink::Ptr create_gl_texture_video_sink(std::uint32_t texture_id); | 61 | virtual video::Sink::Ptr create_gl_texture_video_sink(std::uint32_t texture_id); |
1754 | 62 | 62 | ||
1755 | 63 | 63 | ||
1756 | === modified file 'src/core/media/player_skeleton.cpp' | |||
1757 | --- src/core/media/player_skeleton.cpp 2015-03-16 15:38:27 +0000 | |||
1758 | +++ src/core/media/player_skeleton.cpp 2015-03-16 15:38:27 +0000 | |||
1759 | @@ -17,15 +17,16 @@ | |||
1760 | 17 | * Jim Hodapp <jim.hodapp@canonical.com> | 17 | * Jim Hodapp <jim.hodapp@canonical.com> |
1761 | 18 | */ | 18 | */ |
1762 | 19 | 19 | ||
1763 | 20 | #include "apparmor.h" | ||
1764 | 21 | #include "codec.h" | 20 | #include "codec.h" |
1765 | 22 | #include "engine.h" | 21 | #include "engine.h" |
1766 | 22 | #include "external_services.h" | ||
1767 | 23 | #include "player_skeleton.h" | 23 | #include "player_skeleton.h" |
1768 | 24 | #include "player_traits.h" | 24 | #include "player_traits.h" |
1769 | 25 | #include "property_stub.h" | 25 | #include "property_stub.h" |
1770 | 26 | #include "the_session_bus.h" | 26 | #include "the_session_bus.h" |
1771 | 27 | #include "xesam.h" | 27 | #include "xesam.h" |
1772 | 28 | 28 | ||
1773 | 29 | #include "apparmor/ubuntu.h" | ||
1774 | 29 | #include "mpris/media_player2.h" | 30 | #include "mpris/media_player2.h" |
1775 | 30 | #include "mpris/metadata.h" | 31 | #include "mpris/metadata.h" |
1776 | 31 | #include "mpris/player.h" | 32 | #include "mpris/player.h" |
1777 | @@ -44,19 +45,20 @@ | |||
1778 | 44 | struct media::PlayerSkeleton::Private | 45 | struct media::PlayerSkeleton::Private |
1779 | 45 | { | 46 | { |
1780 | 46 | Private(media::PlayerSkeleton* player, | 47 | Private(media::PlayerSkeleton* player, |
1781 | 47 | const std::string& identity, | ||
1782 | 48 | const std::shared_ptr<core::dbus::Bus>& bus, | 48 | const std::shared_ptr<core::dbus::Bus>& bus, |
1784 | 49 | const std::shared_ptr<core::dbus::Object>& session) | 49 | const std::shared_ptr<core::dbus::Object>& session, |
1785 | 50 | const apparmor::ubuntu::RequestContextResolver::Ptr& request_context_resolver, | ||
1786 | 51 | const apparmor::ubuntu::RequestAuthenticator::Ptr& request_authenticator) | ||
1787 | 50 | : impl(player), | 52 | : impl(player), |
1788 | 51 | identity(identity), | ||
1789 | 52 | bus(bus), | 53 | bus(bus), |
1790 | 53 | object(session), | 54 | object(session), |
1793 | 54 | apparmor_session(nullptr), | 55 | request_context_resolver{request_context_resolver}, |
1794 | 55 | dbus_stub{bus}, | 56 | request_authenticator{request_authenticator}, |
1795 | 56 | skeleton{mpris::Player::Skeleton::Configuration{bus, session, mpris::Player::Skeleton::Configuration::Defaults{}}}, | 57 | skeleton{mpris::Player::Skeleton::Configuration{bus, session, mpris::Player::Skeleton::Configuration::Defaults{}}}, |
1796 | 57 | signals | 58 | signals |
1797 | 58 | { | 59 | { |
1798 | 59 | skeleton.signals.seeked_to, | 60 | skeleton.signals.seeked_to, |
1799 | 61 | skeleton.signals.about_to_finish, | ||
1800 | 60 | skeleton.signals.end_of_stream, | 62 | skeleton.signals.end_of_stream, |
1801 | 61 | skeleton.signals.playback_status_changed, | 63 | skeleton.signals.playback_status_changed, |
1802 | 62 | skeleton.signals.video_dimension_changed, | 64 | skeleton.signals.video_dimension_changed, |
1803 | @@ -163,82 +165,6 @@ | |||
1804 | 163 | bus->send(reply); | 165 | bus->send(reply); |
1805 | 164 | } | 166 | } |
1806 | 165 | 167 | ||
1807 | 166 | bool does_client_have_access(const std::string& context, const std::string& uri) | ||
1808 | 167 | { | ||
1809 | 168 | if (context.empty() || uri.empty()) | ||
1810 | 169 | { | ||
1811 | 170 | std::cout << "Client denied access since context or uri are empty" << std::endl; | ||
1812 | 171 | return false; | ||
1813 | 172 | } | ||
1814 | 173 | |||
1815 | 174 | if (context == "unconfined") | ||
1816 | 175 | { | ||
1817 | 176 | std::cout << "Client allowed access since it's unconfined" << std::endl; | ||
1818 | 177 | return true; | ||
1819 | 178 | } | ||
1820 | 179 | |||
1821 | 180 | size_t pos = context.find_first_of('_'); | ||
1822 | 181 | if (pos == std::string::npos) | ||
1823 | 182 | { | ||
1824 | 183 | std::cout << "Client denied access since it's an invalid apparmor security context" << std::endl; | ||
1825 | 184 | return false; | ||
1826 | 185 | } | ||
1827 | 186 | |||
1828 | 187 | const std::string pkgname = context.substr(0, pos); | ||
1829 | 188 | std::cout << "client pkgname: " << pkgname << std::endl; | ||
1830 | 189 | std::cout << "uri: " << uri << std::endl; | ||
1831 | 190 | |||
1832 | 191 | // All confined apps can access their own files | ||
1833 | 192 | if (uri.find(std::string(".local/share/" + pkgname + "/")) != std::string::npos | ||
1834 | 193 | || uri.find(std::string(".cache/" + pkgname + "/")) != std::string::npos) | ||
1835 | 194 | { | ||
1836 | 195 | std::cout << "Client can access content in ~/.local/share/" << pkgname << " or ~/.cache/" << pkgname << std::endl; | ||
1837 | 196 | return true; | ||
1838 | 197 | } | ||
1839 | 198 | else if (uri.find(std::string("opt/click.ubuntu.com/")) != std::string::npos | ||
1840 | 199 | && uri.find(pkgname) != std::string::npos) | ||
1841 | 200 | { | ||
1842 | 201 | std::cout << "Client can access content in own opt directory" << std::endl; | ||
1843 | 202 | return true; | ||
1844 | 203 | } | ||
1845 | 204 | else if ((uri.find(std::string("/system/media/audio/ui/")) != std::string::npos | ||
1846 | 205 | || uri.find(std::string("/android/system/media/audio/ui/")) != std::string::npos) | ||
1847 | 206 | && pkgname == "com.ubuntu.camera") | ||
1848 | 207 | { | ||
1849 | 208 | std::cout << "Camera app can access ui sounds" << std::endl; | ||
1850 | 209 | return true; | ||
1851 | 210 | } | ||
1852 | 211 | // TODO: Check if the trust store previously allowed direct access to uri | ||
1853 | 212 | |||
1854 | 213 | // Check in ~/Music and ~/Videos | ||
1855 | 214 | // TODO: when the trust store lands, check it to see if this app can access the dirs and | ||
1856 | 215 | // then remove the explicit whitelist of the music-app, and gallery-app | ||
1857 | 216 | else if ((pkgname == "com.ubuntu.music" || pkgname == "com.ubuntu.gallery") && | ||
1858 | 217 | (uri.find(std::string("Music/")) != std::string::npos | ||
1859 | 218 | || uri.find(std::string("Videos/")) != std::string::npos | ||
1860 | 219 | || uri.find(std::string("/media")) != std::string::npos)) | ||
1861 | 220 | { | ||
1862 | 221 | std::cout << "Client can access content in ~/Music or ~/Videos" << std::endl; | ||
1863 | 222 | return true; | ||
1864 | 223 | } | ||
1865 | 224 | else if (uri.find(std::string("/usr/share/sounds")) != std::string::npos) | ||
1866 | 225 | { | ||
1867 | 226 | std::cout << "Client can access content in /usr/share/sounds" << std::endl; | ||
1868 | 227 | return true; | ||
1869 | 228 | } | ||
1870 | 229 | else if (uri.find(std::string("http://")) != std::string::npos | ||
1871 | 230 | || uri.find(std::string("rtsp://")) != std::string::npos) | ||
1872 | 231 | { | ||
1873 | 232 | std::cout << "Client can access streaming content" << std::endl; | ||
1874 | 233 | return true; | ||
1875 | 234 | } | ||
1876 | 235 | else | ||
1877 | 236 | { | ||
1878 | 237 | std::cout << "Client denied access to open_uri()" << std::endl; | ||
1879 | 238 | return false; | ||
1880 | 239 | } | ||
1881 | 240 | } | ||
1882 | 241 | |||
1883 | 242 | void handle_key(const core::dbus::Message::Ptr& in) | 168 | void handle_key(const core::dbus::Message::Ptr& in) |
1884 | 243 | { | 169 | { |
1885 | 244 | auto reply = dbus::Message::make_method_return(in); | 170 | auto reply = dbus::Message::make_method_return(in); |
1886 | @@ -248,15 +174,15 @@ | |||
1887 | 248 | 174 | ||
1888 | 249 | void handle_open_uri(const core::dbus::Message::Ptr& in) | 175 | void handle_open_uri(const core::dbus::Message::Ptr& in) |
1889 | 250 | { | 176 | { |
1891 | 251 | dbus_stub.get_connection_app_armor_security_async(in->sender(), [this, in](const std::string& profile) | 177 | request_context_resolver->resolve_context_for_dbus_name_async(in->sender(), [this, in](const media::apparmor::ubuntu::Context& context) |
1892 | 252 | { | 178 | { |
1893 | 253 | Track::UriType uri; | 179 | Track::UriType uri; |
1894 | 254 | in->reader() >> uri; | 180 | in->reader() >> uri; |
1895 | 255 | 181 | ||
1897 | 256 | bool have_access = does_client_have_access(profile, uri); | 182 | auto result = request_authenticator->authenticate_open_uri_request(context, uri); |
1898 | 257 | 183 | ||
1899 | 258 | auto reply = dbus::Message::make_method_return(in); | 184 | auto reply = dbus::Message::make_method_return(in); |
1901 | 259 | reply->writer() << (have_access ? impl->open_uri(uri) : false); | 185 | reply->writer() << (std::get<0>(result) ? impl->open_uri(uri) : false); |
1902 | 260 | 186 | ||
1903 | 261 | bus->send(reply); | 187 | bus->send(reply); |
1904 | 262 | }); | 188 | }); |
1905 | @@ -264,16 +190,16 @@ | |||
1906 | 264 | 190 | ||
1907 | 265 | void handle_open_uri_extended(const core::dbus::Message::Ptr& in) | 191 | void handle_open_uri_extended(const core::dbus::Message::Ptr& in) |
1908 | 266 | { | 192 | { |
1910 | 267 | dbus_stub.get_connection_app_armor_security_async(in->sender(), [this, in](const std::string& profile) | 193 | request_context_resolver->resolve_context_for_dbus_name_async(in->sender(), [this, in](const media::apparmor::ubuntu::Context& context) |
1911 | 268 | { | 194 | { |
1912 | 269 | Track::UriType uri; | 195 | Track::UriType uri; |
1913 | 270 | Player::HeadersType headers; | 196 | Player::HeadersType headers; |
1914 | 271 | 197 | ||
1915 | 272 | in->reader() >> uri >> headers; | 198 | in->reader() >> uri >> headers; |
1916 | 273 | 199 | ||
1918 | 274 | bool have_access = does_client_have_access(profile, uri); | 200 | auto result = request_authenticator->authenticate_open_uri_request(context, uri); |
1919 | 275 | auto reply = dbus::Message::make_method_return(in); | 201 | auto reply = dbus::Message::make_method_return(in); |
1921 | 276 | reply->writer() << (have_access ? impl->open_uri(uri, headers) : false); | 202 | reply->writer() << (std::get<0>(result) ? impl->open_uri(uri, headers) : false); |
1922 | 277 | 203 | ||
1923 | 278 | bus->send(reply); | 204 | bus->send(reply); |
1924 | 279 | }); | 205 | }); |
1925 | @@ -301,12 +227,10 @@ | |||
1926 | 301 | } | 227 | } |
1927 | 302 | 228 | ||
1928 | 303 | media::PlayerSkeleton* impl; | 229 | media::PlayerSkeleton* impl; |
1929 | 304 | std::string identity; | ||
1930 | 305 | dbus::Bus::Ptr bus; | 230 | dbus::Bus::Ptr bus; |
1931 | 306 | dbus::Object::Ptr object; | 231 | dbus::Object::Ptr object; |
1935 | 307 | dbus::Object::Ptr apparmor_session; | 232 | media::apparmor::ubuntu::RequestContextResolver::Ptr request_context_resolver; |
1936 | 308 | 233 | media::apparmor::ubuntu::RequestAuthenticator::Ptr request_authenticator; | |
1934 | 309 | org::freedesktop::dbus::DBus::Stub dbus_stub; | ||
1937 | 310 | 234 | ||
1938 | 311 | mpris::Player::Skeleton skeleton; | 235 | mpris::Player::Skeleton skeleton; |
1939 | 312 | 236 | ||
1940 | @@ -314,11 +238,13 @@ | |||
1941 | 314 | { | 238 | { |
1942 | 315 | typedef core::dbus::Signal<mpris::Player::Signals::Seeked, mpris::Player::Signals::Seeked::ArgumentType> DBusSeekedToSignal; | 239 | typedef core::dbus::Signal<mpris::Player::Signals::Seeked, mpris::Player::Signals::Seeked::ArgumentType> DBusSeekedToSignal; |
1943 | 316 | typedef core::dbus::Signal<mpris::Player::Signals::EndOfStream, mpris::Player::Signals::EndOfStream::ArgumentType> DBusEndOfStreamSignal; | 240 | typedef core::dbus::Signal<mpris::Player::Signals::EndOfStream, mpris::Player::Signals::EndOfStream::ArgumentType> DBusEndOfStreamSignal; |
1944 | 241 | typedef core::dbus::Signal<mpris::Player::Signals::AboutToFinish, mpris::Player::Signals::AboutToFinish::ArgumentType> DBusAboutToFinishSignal; | ||
1945 | 317 | typedef core::dbus::Signal<mpris::Player::Signals::PlaybackStatusChanged, mpris::Player::Signals::PlaybackStatusChanged::ArgumentType> DBusPlaybackStatusChangedSignal; | 242 | typedef core::dbus::Signal<mpris::Player::Signals::PlaybackStatusChanged, mpris::Player::Signals::PlaybackStatusChanged::ArgumentType> DBusPlaybackStatusChangedSignal; |
1946 | 318 | typedef core::dbus::Signal<mpris::Player::Signals::VideoDimensionChanged, mpris::Player::Signals::VideoDimensionChanged::ArgumentType> DBusVideoDimensionChangedSignal; | 243 | typedef core::dbus::Signal<mpris::Player::Signals::VideoDimensionChanged, mpris::Player::Signals::VideoDimensionChanged::ArgumentType> DBusVideoDimensionChangedSignal; |
1947 | 319 | typedef core::dbus::Signal<mpris::Player::Signals::Error, mpris::Player::Signals::Error::ArgumentType> DBusErrorSignal; | 244 | typedef core::dbus::Signal<mpris::Player::Signals::Error, mpris::Player::Signals::Error::ArgumentType> DBusErrorSignal; |
1948 | 320 | 245 | ||
1949 | 321 | Signals(const std::shared_ptr<DBusSeekedToSignal>& remote_seeked, | 246 | Signals(const std::shared_ptr<DBusSeekedToSignal>& remote_seeked, |
1950 | 247 | const std::shared_ptr<DBusAboutToFinishSignal>& remote_atf, | ||
1951 | 322 | const std::shared_ptr<DBusEndOfStreamSignal>& remote_eos, | 248 | const std::shared_ptr<DBusEndOfStreamSignal>& remote_eos, |
1952 | 323 | const std::shared_ptr<DBusPlaybackStatusChangedSignal>& remote_playback_status_changed, | 249 | const std::shared_ptr<DBusPlaybackStatusChangedSignal>& remote_playback_status_changed, |
1953 | 324 | const std::shared_ptr<DBusVideoDimensionChangedSignal>& remote_video_dimension_changed, | 250 | const std::shared_ptr<DBusVideoDimensionChangedSignal>& remote_video_dimension_changed, |
1954 | @@ -329,6 +255,11 @@ | |||
1955 | 329 | remote_seeked->emit(value); | 255 | remote_seeked->emit(value); |
1956 | 330 | }); | 256 | }); |
1957 | 331 | 257 | ||
1958 | 258 | about_to_finish.connect([remote_atf]() | ||
1959 | 259 | { | ||
1960 | 260 | remote_atf->emit(); | ||
1961 | 261 | }); | ||
1962 | 262 | |||
1963 | 332 | end_of_stream.connect([remote_eos]() | 263 | end_of_stream.connect([remote_eos]() |
1964 | 333 | { | 264 | { |
1965 | 334 | remote_eos->emit(); | 265 | remote_eos->emit(); |
1966 | @@ -351,6 +282,7 @@ | |||
1967 | 351 | } | 282 | } |
1968 | 352 | 283 | ||
1969 | 353 | core::Signal<int64_t> seeked_to; | 284 | core::Signal<int64_t> seeked_to; |
1970 | 285 | core::Signal<void> about_to_finish; | ||
1971 | 354 | core::Signal<void> end_of_stream; | 286 | core::Signal<void> end_of_stream; |
1972 | 355 | core::Signal<media::Player::PlaybackStatus> playback_status_changed; | 287 | core::Signal<media::Player::PlaybackStatus> playback_status_changed; |
1973 | 356 | core::Signal<media::video::Dimensions> video_dimension_changed; | 288 | core::Signal<media::video::Dimensions> video_dimension_changed; |
1974 | @@ -360,7 +292,7 @@ | |||
1975 | 360 | }; | 292 | }; |
1976 | 361 | 293 | ||
1977 | 362 | media::PlayerSkeleton::PlayerSkeleton(const media::PlayerSkeleton::Configuration& config) | 294 | media::PlayerSkeleton::PlayerSkeleton(const media::PlayerSkeleton::Configuration& config) |
1979 | 363 | : d(new Private{this, config.identity, config.bus, config.session}) | 295 | : d(new Private{this, config.bus, config.session, config.request_context_resolver, config.request_authenticator}) |
1980 | 364 | { | 296 | { |
1981 | 365 | // Setup method handlers for mpris::Player methods. | 297 | // Setup method handlers for mpris::Player methods. |
1982 | 366 | auto next = std::bind(&Private::handle_next, d, std::placeholders::_1); | 298 | auto next = std::bind(&Private::handle_next, d, std::placeholders::_1); |
1983 | @@ -635,6 +567,16 @@ | |||
1984 | 635 | return d->signals.seeked_to; | 567 | return d->signals.seeked_to; |
1985 | 636 | } | 568 | } |
1986 | 637 | 569 | ||
1987 | 570 | const core::Signal<void>& media::PlayerSkeleton::about_to_finish() const | ||
1988 | 571 | { | ||
1989 | 572 | return d->signals.about_to_finish; | ||
1990 | 573 | } | ||
1991 | 574 | |||
1992 | 575 | core::Signal<void>& media::PlayerSkeleton::about_to_finish() | ||
1993 | 576 | { | ||
1994 | 577 | return d->signals.about_to_finish; | ||
1995 | 578 | } | ||
1996 | 579 | |||
1997 | 638 | const core::Signal<void>& media::PlayerSkeleton::end_of_stream() const | 580 | const core::Signal<void>& media::PlayerSkeleton::end_of_stream() const |
1998 | 639 | { | 581 | { |
1999 | 640 | return d->signals.end_of_stream; | 582 | return d->signals.end_of_stream; |
2000 | 641 | 583 | ||
2001 | === modified file 'src/core/media/player_skeleton.h' | |||
2002 | --- src/core/media/player_skeleton.h 2015-03-16 15:38:27 +0000 | |||
2003 | +++ src/core/media/player_skeleton.h 2015-03-16 15:38:27 +0000 | |||
2004 | @@ -24,6 +24,7 @@ | |||
2005 | 24 | 24 | ||
2006 | 25 | #include "player_traits.h" | 25 | #include "player_traits.h" |
2007 | 26 | 26 | ||
2008 | 27 | #include "apparmor/ubuntu.h" | ||
2009 | 27 | #include "mpris/player.h" | 28 | #include "mpris/player.h" |
2010 | 28 | 29 | ||
2011 | 29 | #include <core/dbus/skeleton.h> | 30 | #include <core/dbus/skeleton.h> |
2012 | @@ -37,11 +38,29 @@ | |||
2013 | 37 | { | 38 | { |
2014 | 38 | namespace media | 39 | namespace media |
2015 | 39 | { | 40 | { |
2016 | 41 | namespace helper | ||
2017 | 42 | { | ||
2018 | 43 | struct ExternalServices; | ||
2019 | 44 | } | ||
2020 | 45 | |||
2021 | 40 | class Service; | 46 | class Service; |
2022 | 41 | 47 | ||
2023 | 42 | class PlayerSkeleton : public core::ubuntu::media::Player | 48 | class PlayerSkeleton : public core::ubuntu::media::Player |
2024 | 43 | { | 49 | { |
2025 | 44 | public: | 50 | public: |
2026 | 51 | // All creation time arguments go here. | ||
2027 | 52 | struct Configuration | ||
2028 | 53 | { | ||
2029 | 54 | // The bus connection we are associated with. | ||
2030 | 55 | std::shared_ptr<core::dbus::Bus> bus; | ||
2031 | 56 | // The session object that we want to expose the skeleton upon. | ||
2032 | 57 | std::shared_ptr<core::dbus::Object> session; | ||
2033 | 58 | // Our functional dependencies. | ||
2034 | 59 | apparmor::ubuntu::RequestContextResolver::Ptr request_context_resolver; | ||
2035 | 60 | apparmor::ubuntu::RequestAuthenticator::Ptr request_authenticator; | ||
2036 | 61 | }; | ||
2037 | 62 | |||
2038 | 63 | PlayerSkeleton(const Configuration& configuration); | ||
2039 | 45 | ~PlayerSkeleton(); | 64 | ~PlayerSkeleton(); |
2040 | 46 | 65 | ||
2041 | 47 | virtual const core::Property<bool>& can_play() const; | 66 | virtual const core::Property<bool>& can_play() const; |
2042 | @@ -73,26 +92,11 @@ | |||
2043 | 73 | virtual core::Property<Lifetime>& lifetime(); | 92 | virtual core::Property<Lifetime>& lifetime(); |
2044 | 74 | 93 | ||
2045 | 75 | virtual const core::Signal<int64_t>& seeked_to() const; | 94 | virtual const core::Signal<int64_t>& seeked_to() const; |
2046 | 95 | virtual const core::Signal<void>& about_to_finish() const; | ||
2047 | 76 | virtual const core::Signal<void>& end_of_stream() const; | 96 | virtual const core::Signal<void>& end_of_stream() const; |
2048 | 77 | virtual core::Signal<PlaybackStatus>& playback_status_changed(); | ||
2049 | 78 | virtual const core::Signal<video::Dimensions>& video_dimension_changed() const; | 97 | virtual const core::Signal<video::Dimensions>& video_dimension_changed() const; |
2050 | 79 | virtual const core::Signal<Error>& error() const; | 98 | virtual const core::Signal<Error>& error() const; |
2051 | 80 | 99 | ||
2052 | 81 | protected: | ||
2053 | 82 | // All creation time arguments go here. | ||
2054 | 83 | struct Configuration | ||
2055 | 84 | { | ||
2056 | 85 | // The bus connection we are associated with. | ||
2057 | 86 | std::shared_ptr<core::dbus::Bus> bus; | ||
2058 | 87 | // The session object that we want to expose the skeleton upon. | ||
2059 | 88 | std::shared_ptr<core::dbus::Object> session; | ||
2060 | 89 | // Our identity, an identifier we pass out to other parts of the system. | ||
2061 | 90 | // Defaults to the short app id (${PKG_NAME}_${APP}). | ||
2062 | 91 | std::string identity; | ||
2063 | 92 | }; | ||
2064 | 93 | |||
2065 | 94 | PlayerSkeleton(const Configuration& configuration); | ||
2066 | 95 | |||
2067 | 96 | // These properties are not exposed to the client, but still need to be | 100 | // These properties are not exposed to the client, but still need to be |
2068 | 97 | // able to be settable from within the Player: | 101 | // able to be settable from within the Player: |
2069 | 98 | virtual core::Property<PlaybackStatus>& playback_status(); | 102 | virtual core::Property<PlaybackStatus>& playback_status(); |
2070 | @@ -111,7 +115,9 @@ | |||
2071 | 111 | virtual core::Property<Orientation>& orientation(); | 115 | virtual core::Property<Orientation>& orientation(); |
2072 | 112 | 116 | ||
2073 | 113 | virtual core::Signal<int64_t>& seeked_to(); | 117 | virtual core::Signal<int64_t>& seeked_to(); |
2074 | 118 | virtual core::Signal<void>& about_to_finish(); | ||
2075 | 114 | virtual core::Signal<void>& end_of_stream(); | 119 | virtual core::Signal<void>& end_of_stream(); |
2076 | 120 | virtual core::Signal<PlaybackStatus>& playback_status_changed(); | ||
2077 | 115 | virtual core::Signal<video::Dimensions>& video_dimension_changed(); | 121 | virtual core::Signal<video::Dimensions>& video_dimension_changed(); |
2078 | 116 | virtual core::Signal<Error>& error(); | 122 | virtual core::Signal<Error>& error(); |
2079 | 117 | 123 | ||
2080 | 118 | 124 | ||
2081 | === modified file 'src/core/media/player_stub.cpp' | |||
2082 | --- src/core/media/player_stub.cpp 2015-03-16 15:38:27 +0000 | |||
2083 | +++ src/core/media/player_stub.cpp 2015-03-16 15:38:27 +0000 | |||
2084 | @@ -76,6 +76,7 @@ | |||
2085 | 76 | signals | 76 | signals |
2086 | 77 | { | 77 | { |
2087 | 78 | object->get_signal<mpris::Player::Signals::Seeked>(), | 78 | object->get_signal<mpris::Player::Signals::Seeked>(), |
2088 | 79 | object->get_signal<mpris::Player::Signals::AboutToFinish>(), | ||
2089 | 79 | object->get_signal<mpris::Player::Signals::EndOfStream>(), | 80 | object->get_signal<mpris::Player::Signals::EndOfStream>(), |
2090 | 80 | object->get_signal<mpris::Player::Signals::PlaybackStatusChanged>(), | 81 | object->get_signal<mpris::Player::Signals::PlaybackStatusChanged>(), |
2091 | 81 | object->get_signal<mpris::Player::Signals::VideoDimensionChanged>(), | 82 | object->get_signal<mpris::Player::Signals::VideoDimensionChanged>(), |
2092 | @@ -122,17 +123,20 @@ | |||
2093 | 122 | struct Signals | 123 | struct Signals |
2094 | 123 | { | 124 | { |
2095 | 124 | typedef core::dbus::Signal<mpris::Player::Signals::Seeked, mpris::Player::Signals::Seeked::ArgumentType> DBusSeekedToSignal; | 125 | typedef core::dbus::Signal<mpris::Player::Signals::Seeked, mpris::Player::Signals::Seeked::ArgumentType> DBusSeekedToSignal; |
2096 | 126 | typedef core::dbus::Signal<mpris::Player::Signals::AboutToFinish, mpris::Player::Signals::AboutToFinish::ArgumentType> DBusAboutToFinishSignal; | ||
2097 | 125 | typedef core::dbus::Signal<mpris::Player::Signals::EndOfStream, mpris::Player::Signals::EndOfStream::ArgumentType> DBusEndOfStreamSignal; | 127 | typedef core::dbus::Signal<mpris::Player::Signals::EndOfStream, mpris::Player::Signals::EndOfStream::ArgumentType> DBusEndOfStreamSignal; |
2098 | 126 | typedef core::dbus::Signal<mpris::Player::Signals::PlaybackStatusChanged, mpris::Player::Signals::PlaybackStatusChanged::ArgumentType> DBusPlaybackStatusChangedSignal; | 128 | typedef core::dbus::Signal<mpris::Player::Signals::PlaybackStatusChanged, mpris::Player::Signals::PlaybackStatusChanged::ArgumentType> DBusPlaybackStatusChangedSignal; |
2099 | 127 | typedef core::dbus::Signal<mpris::Player::Signals::VideoDimensionChanged, mpris::Player::Signals::VideoDimensionChanged::ArgumentType> DBusVideoDimensionChangedSignal; | 129 | typedef core::dbus::Signal<mpris::Player::Signals::VideoDimensionChanged, mpris::Player::Signals::VideoDimensionChanged::ArgumentType> DBusVideoDimensionChangedSignal; |
2100 | 128 | typedef core::dbus::Signal<mpris::Player::Signals::Error, mpris::Player::Signals::Error::ArgumentType> DBusErrorSignal; | 130 | typedef core::dbus::Signal<mpris::Player::Signals::Error, mpris::Player::Signals::Error::ArgumentType> DBusErrorSignal; |
2101 | 129 | 131 | ||
2102 | 130 | Signals(const std::shared_ptr<DBusSeekedToSignal>& seeked, | 132 | Signals(const std::shared_ptr<DBusSeekedToSignal>& seeked, |
2103 | 133 | const std::shared_ptr<DBusAboutToFinishSignal>& atf, | ||
2104 | 131 | const std::shared_ptr<DBusEndOfStreamSignal>& eos, | 134 | const std::shared_ptr<DBusEndOfStreamSignal>& eos, |
2105 | 132 | const std::shared_ptr<DBusPlaybackStatusChangedSignal>& status, | 135 | const std::shared_ptr<DBusPlaybackStatusChangedSignal>& status, |
2106 | 133 | const std::shared_ptr<DBusVideoDimensionChangedSignal>& d, | 136 | const std::shared_ptr<DBusVideoDimensionChangedSignal>& d, |
2107 | 134 | const std::shared_ptr<DBusErrorSignal>& e) | 137 | const std::shared_ptr<DBusErrorSignal>& e) |
2108 | 135 | : seeked_to(), | 138 | : seeked_to(), |
2109 | 139 | about_to_finish(), | ||
2110 | 136 | end_of_stream(), | 140 | end_of_stream(), |
2111 | 137 | playback_status_changed(), | 141 | playback_status_changed(), |
2112 | 138 | video_dimension_changed(), | 142 | video_dimension_changed(), |
2113 | @@ -140,6 +144,7 @@ | |||
2114 | 140 | dbus | 144 | dbus |
2115 | 141 | { | 145 | { |
2116 | 142 | seeked, | 146 | seeked, |
2117 | 147 | atf, | ||
2118 | 143 | eos, | 148 | eos, |
2119 | 144 | status, | 149 | status, |
2120 | 145 | d, | 150 | d, |
2121 | @@ -152,6 +157,12 @@ | |||
2122 | 152 | seeked_to(value); | 157 | seeked_to(value); |
2123 | 153 | }); | 158 | }); |
2124 | 154 | 159 | ||
2125 | 160 | dbus.about_to_finish->connect([this]() | ||
2126 | 161 | { | ||
2127 | 162 | std::cout << "AboutToFinish signal arrived via the bus." << std::endl; | ||
2128 | 163 | about_to_finish(); | ||
2129 | 164 | }); | ||
2130 | 165 | |||
2131 | 155 | dbus.end_of_stream->connect([this]() | 166 | dbus.end_of_stream->connect([this]() |
2132 | 156 | { | 167 | { |
2133 | 157 | std::cout << "EndOfStream signal arrived via the bus." << std::endl; | 168 | std::cout << "EndOfStream signal arrived via the bus." << std::endl; |
2134 | @@ -178,6 +189,7 @@ | |||
2135 | 178 | } | 189 | } |
2136 | 179 | 190 | ||
2137 | 180 | core::Signal<int64_t> seeked_to; | 191 | core::Signal<int64_t> seeked_to; |
2138 | 192 | core::Signal<void> about_to_finish; | ||
2139 | 181 | core::Signal<void> end_of_stream; | 193 | core::Signal<void> end_of_stream; |
2140 | 182 | core::Signal<media::Player::PlaybackStatus> playback_status_changed; | 194 | core::Signal<media::Player::PlaybackStatus> playback_status_changed; |
2141 | 183 | core::Signal<media::video::Dimensions> video_dimension_changed; | 195 | core::Signal<media::video::Dimensions> video_dimension_changed; |
2142 | @@ -186,6 +198,7 @@ | |||
2143 | 186 | struct DBus | 198 | struct DBus |
2144 | 187 | { | 199 | { |
2145 | 188 | std::shared_ptr<DBusSeekedToSignal> seeked_to; | 200 | std::shared_ptr<DBusSeekedToSignal> seeked_to; |
2146 | 201 | std::shared_ptr<DBusAboutToFinishSignal> about_to_finish; | ||
2147 | 189 | std::shared_ptr<DBusEndOfStreamSignal> end_of_stream; | 202 | std::shared_ptr<DBusEndOfStreamSignal> end_of_stream; |
2148 | 190 | std::shared_ptr<DBusPlaybackStatusChangedSignal> playback_status_changed; | 203 | std::shared_ptr<DBusPlaybackStatusChangedSignal> playback_status_changed; |
2149 | 191 | std::shared_ptr<DBusVideoDimensionChangedSignal> video_dimension_changed; | 204 | std::shared_ptr<DBusVideoDimensionChangedSignal> video_dimension_changed; |
2150 | @@ -434,6 +447,11 @@ | |||
2151 | 434 | return d->signals.seeked_to; | 447 | return d->signals.seeked_to; |
2152 | 435 | } | 448 | } |
2153 | 436 | 449 | ||
2154 | 450 | const core::Signal<void>& media::PlayerStub::about_to_finish() const | ||
2155 | 451 | { | ||
2156 | 452 | return d->signals.about_to_finish; | ||
2157 | 453 | } | ||
2158 | 454 | |||
2159 | 437 | const core::Signal<void>& media::PlayerStub::end_of_stream() const | 455 | const core::Signal<void>& media::PlayerStub::end_of_stream() const |
2160 | 438 | { | 456 | { |
2161 | 439 | return d->signals.end_of_stream; | 457 | return d->signals.end_of_stream; |
2162 | 440 | 458 | ||
2163 | === modified file 'src/core/media/player_stub.h' | |||
2164 | --- src/core/media/player_stub.h 2015-03-16 15:38:27 +0000 | |||
2165 | +++ src/core/media/player_stub.h 2015-03-16 15:38:27 +0000 | |||
2166 | @@ -86,6 +86,7 @@ | |||
2167 | 86 | virtual core::Property<Lifetime>& lifetime(); | 86 | virtual core::Property<Lifetime>& lifetime(); |
2168 | 87 | 87 | ||
2169 | 88 | virtual const core::Signal<int64_t>& seeked_to() const; | 88 | virtual const core::Signal<int64_t>& seeked_to() const; |
2170 | 89 | virtual const core::Signal<void>& about_to_finish() const; | ||
2171 | 89 | virtual const core::Signal<void>& end_of_stream() const; | 90 | virtual const core::Signal<void>& end_of_stream() const; |
2172 | 90 | virtual core::Signal<PlaybackStatus>& playback_status_changed(); | 91 | virtual core::Signal<PlaybackStatus>& playback_status_changed(); |
2173 | 91 | virtual const core::Signal<video::Dimensions>& video_dimension_changed() const; | 92 | virtual const core::Signal<video::Dimensions>& video_dimension_changed() const; |
2174 | 92 | 93 | ||
2175 | === modified file 'src/core/media/power/state_controller.cpp' | |||
2176 | --- src/core/media/power/state_controller.cpp 2015-03-16 15:38:27 +0000 | |||
2177 | +++ src/core/media/power/state_controller.cpp 2015-03-16 15:38:27 +0000 | |||
2178 | @@ -128,42 +128,38 @@ | |||
2179 | 128 | if (cookie == the_invalid_cookie) | 128 | if (cookie == the_invalid_cookie) |
2180 | 129 | return; | 129 | return; |
2181 | 130 | 130 | ||
2183 | 131 | std::weak_ptr<DisplayStateLock> wp{shared_from_this()}; | 131 | // We make sure that we keep ourselves alive to make sure |
2184 | 132 | // that release requests are always correctly issued. | ||
2185 | 133 | auto sp = shared_from_this(); | ||
2186 | 132 | 134 | ||
2187 | 133 | auto current_cookie(cookie); | 135 | auto current_cookie(cookie); |
2188 | 134 | 136 | ||
2189 | 135 | timeout.expires_from_now(timeout_for_release()); | 137 | timeout.expires_from_now(timeout_for_release()); |
2191 | 136 | timeout.async_wait([wp, state, current_cookie](const boost::system::error_code& ec) | 138 | timeout.async_wait([sp, state, current_cookie](const boost::system::error_code& ec) |
2192 | 137 | { | 139 | { |
2193 | 138 | // We only return early from the timeout handler if the operation has been | 140 | // We only return early from the timeout handler if the operation has been |
2194 | 139 | // explicitly aborted before. | 141 | // explicitly aborted before. |
2195 | 140 | if (ec == boost::asio::error::operation_aborted) | 142 | if (ec == boost::asio::error::operation_aborted) |
2196 | 141 | return; | 143 | return; |
2197 | 142 | 144 | ||
2202 | 143 | if (auto sp = wp.lock()) | 145 | sp->object->invoke_method_asynchronously_with_callback<com::canonical::Unity::Screen::removeDisplayOnRequest, void>( |
2203 | 144 | { | 146 | [sp, state, current_cookie](const core::dbus::Result<void>& result) |
2204 | 145 | sp->object->invoke_method_asynchronously_with_callback<com::canonical::Unity::Screen::removeDisplayOnRequest, void>( | 147 | { |
2205 | 146 | [wp, state, current_cookie](const core::dbus::Result<void>& result) | 148 | if (result.is_error()) |
2206 | 147 | { | 149 | { |
2226 | 148 | if (result.is_error()) | 150 | std::cerr << result.error().print() << std::endl; |
2227 | 149 | { | 151 | return; |
2228 | 150 | std::cerr << result.error().print() << std::endl; | 152 | } |
2229 | 151 | return; | 153 | |
2230 | 152 | } | 154 | sp->signals.released(state); |
2231 | 153 | 155 | ||
2232 | 154 | if (auto sp = wp.lock()) | 156 | // We might have issued a different request before and |
2233 | 155 | { | 157 | // only call the display state done if the original cookie |
2234 | 156 | sp->signals.released(state); | 158 | // corresponds to the one we just gave up. |
2235 | 157 | 159 | if (sp->cookie == current_cookie) | |
2236 | 158 | // We might have issued a different request before and | 160 | sp->cookie = the_invalid_cookie; |
2237 | 159 | // only call the display state done if the original cookie | 161 | |
2238 | 160 | // corresponds to the one we just gave up. | 162 | }, current_cookie); |
2220 | 161 | if (sp->cookie == current_cookie) | ||
2221 | 162 | sp->cookie = the_invalid_cookie; | ||
2222 | 163 | } | ||
2223 | 164 | |||
2224 | 165 | }, current_cookie); | ||
2225 | 166 | } | ||
2239 | 167 | }); | 163 | }); |
2240 | 168 | } | 164 | } |
2241 | 169 | 165 | ||
2242 | 170 | 166 | ||
2243 | === modified file 'src/core/media/server/server.cpp' | |||
2244 | --- src/core/media/server/server.cpp 2015-03-16 15:38:27 +0000 | |||
2245 | +++ src/core/media/server/server.cpp 2015-03-16 15:38:27 +0000 | |||
2246 | @@ -20,6 +20,7 @@ | |||
2247 | 20 | #include <core/media/player.h> | 20 | #include <core/media/player.h> |
2248 | 21 | #include <core/media/track_list.h> | 21 | #include <core/media/track_list.h> |
2249 | 22 | 22 | ||
2250 | 23 | #include "core/media/hashed_keyed_player_store.h" | ||
2251 | 23 | #include "core/media/service_implementation.h" | 24 | #include "core/media/service_implementation.h" |
2252 | 24 | 25 | ||
2253 | 25 | #include <core/posix/signal.h> | 26 | #include <core/posix/signal.h> |
2254 | @@ -103,23 +104,37 @@ | |||
2255 | 103 | } | 104 | } |
2256 | 104 | }; | 105 | }; |
2257 | 105 | 106 | ||
2258 | 107 | // Our common player store instance for tracking player instances. | ||
2259 | 108 | auto player_store = std::make_shared<media::HashedKeyedPlayerStore>(); | ||
2260 | 106 | // We assemble the configuration for executing the service now. | 109 | // We assemble the configuration for executing the service now. |
2261 | 107 | media::ServiceImplementation::Configuration service_config | 110 | media::ServiceImplementation::Configuration service_config |
2262 | 108 | { | 111 | { |
2263 | 112 | std::make_shared<media::HashedKeyedPlayerStore>(), | ||
2264 | 109 | external_services | 113 | external_services |
2265 | 110 | }; | 114 | }; |
2266 | 111 | 115 | ||
2268 | 112 | auto service = std::make_shared<media::ServiceImplementation>(service_config); | 116 | auto impl = std::make_shared<media::ServiceImplementation>(media::ServiceImplementation::Configuration |
2269 | 117 | { | ||
2270 | 118 | player_store, | ||
2271 | 119 | external_services | ||
2272 | 120 | }); | ||
2273 | 121 | |||
2274 | 122 | auto skeleton = std::make_shared<media::ServiceSkeleton>(media::ServiceSkeleton::Configuration | ||
2275 | 123 | { | ||
2276 | 124 | impl, | ||
2277 | 125 | player_store, | ||
2278 | 126 | |||
2279 | 127 | }); | ||
2280 | 113 | 128 | ||
2281 | 114 | std::thread service_worker | 129 | std::thread service_worker |
2282 | 115 | { | 130 | { |
2284 | 116 | [&shutdown_requested, service]() | 131 | [&shutdown_requested, skeleton]() |
2285 | 117 | { | 132 | { |
2286 | 118 | while (not shutdown_requested) | 133 | while (not shutdown_requested) |
2287 | 119 | { | 134 | { |
2288 | 120 | try | 135 | try |
2289 | 121 | { | 136 | { |
2291 | 122 | service->run(); | 137 | skeleton->run(); |
2292 | 123 | } | 138 | } |
2293 | 124 | catch (const std::exception& e) | 139 | catch (const std::exception& e) |
2294 | 125 | { | 140 | { |
2295 | @@ -142,7 +157,7 @@ | |||
2296 | 142 | shutdown_requested = true; | 157 | shutdown_requested = true; |
2297 | 143 | 158 | ||
2298 | 144 | // And stop execution of helper and actual service. | 159 | // And stop execution of helper and actual service. |
2300 | 145 | service->stop(); | 160 | skeleton->stop(); |
2301 | 146 | 161 | ||
2302 | 147 | if (service_worker.joinable()) | 162 | if (service_worker.joinable()) |
2303 | 148 | service_worker.join(); | 163 | service_worker.join(); |
2304 | 149 | 164 | ||
2305 | === modified file 'src/core/media/service_implementation.cpp' | |||
2306 | --- src/core/media/service_implementation.cpp 2015-03-16 15:38:27 +0000 | |||
2307 | +++ src/core/media/service_implementation.cpp 2015-03-16 15:38:27 +0000 | |||
2308 | @@ -22,14 +22,16 @@ | |||
2309 | 22 | 22 | ||
2310 | 23 | #include "service_implementation.h" | 23 | #include "service_implementation.h" |
2311 | 24 | 24 | ||
2312 | 25 | #include "apparmor/ubuntu.h" | ||
2313 | 25 | #include "audio/output_observer.h" | 26 | #include "audio/output_observer.h" |
2314 | 26 | #include "client_death_observer.h" | 27 | #include "client_death_observer.h" |
2315 | 27 | #include "call-monitor/call_monitor.h" | ||
2316 | 28 | #include "player_configuration.h" | 28 | #include "player_configuration.h" |
2317 | 29 | #include "player_skeleton.h" | ||
2318 | 29 | #include "player_implementation.h" | 30 | #include "player_implementation.h" |
2319 | 30 | #include "power/battery_observer.h" | 31 | #include "power/battery_observer.h" |
2320 | 31 | #include "power/state_controller.h" | 32 | #include "power/state_controller.h" |
2321 | 32 | #include "recorder_observer.h" | 33 | #include "recorder_observer.h" |
2322 | 34 | #include "telephony/call_monitor.h" | ||
2323 | 33 | 35 | ||
2324 | 34 | #include <boost/asio.hpp> | 36 | #include <boost/asio.hpp> |
2325 | 35 | 37 | ||
2326 | @@ -59,8 +61,10 @@ | |||
2327 | 59 | client_death_observer(media::platform_default_client_death_observer()), | 61 | client_death_observer(media::platform_default_client_death_observer()), |
2328 | 60 | recorder_observer(media::make_platform_default_recorder_observer()), | 62 | recorder_observer(media::make_platform_default_recorder_observer()), |
2329 | 61 | audio_output_observer(media::audio::make_platform_default_output_observer()), | 63 | audio_output_observer(media::audio::make_platform_default_output_observer()), |
2330 | 64 | request_context_resolver(media::apparmor::ubuntu::make_platform_default_request_context_resolver(configuration.external_services)), | ||
2331 | 65 | request_authenticator(media::apparmor::ubuntu::make_platform_default_request_authenticator()), | ||
2332 | 62 | audio_output_state(media::audio::OutputState::Speaker), | 66 | audio_output_state(media::audio::OutputState::Speaker), |
2334 | 63 | call_monitor(new CallMonitor) | 67 | call_monitor(media::telephony::make_platform_default_call_monitor()) |
2335 | 64 | { | 68 | { |
2336 | 65 | } | 69 | } |
2337 | 66 | 70 | ||
2338 | @@ -74,13 +78,16 @@ | |||
2339 | 74 | media::ClientDeathObserver::Ptr client_death_observer; | 78 | media::ClientDeathObserver::Ptr client_death_observer; |
2340 | 75 | media::RecorderObserver::Ptr recorder_observer; | 79 | media::RecorderObserver::Ptr recorder_observer; |
2341 | 76 | media::audio::OutputObserver::Ptr audio_output_observer; | 80 | media::audio::OutputObserver::Ptr audio_output_observer; |
2343 | 77 | media::audio::OutputObserver audio_output_state; | 81 | media::apparmor::ubuntu::RequestContextResolver::Ptr request_context_resolver; |
2344 | 82 | media::apparmor::ubuntu::RequestAuthenticator::Ptr request_authenticator; | ||
2345 | 83 | media::audio::OutputState audio_output_state; | ||
2346 | 78 | 84 | ||
2348 | 79 | std::unique_ptr<CallMonitor> call_monitor; | 85 | media::telephony::CallMonitor::Ptr call_monitor; |
2349 | 80 | std::list<media::Player::PlayerKey> paused_sessions; | 86 | std::list<media::Player::PlayerKey> paused_sessions; |
2350 | 81 | }; | 87 | }; |
2351 | 82 | 88 | ||
2353 | 83 | media::ServiceImplementation::ServiceImplementation(const Configuration& configuration) : d(new Private(configuration)) | 89 | media::ServiceImplementation::ServiceImplementation(const Configuration& configuration) |
2354 | 90 | : d(new Private(configuration)) | ||
2355 | 84 | { | 91 | { |
2356 | 85 | d->battery_observer->level().changed().connect([this](const media::power::Level& level) | 92 | d->battery_observer->level().changed().connect([this](const media::power::Level& level) |
2357 | 86 | { | 93 | { |
2358 | @@ -118,22 +125,20 @@ | |||
2359 | 118 | break; | 125 | break; |
2360 | 119 | case audio::OutputState::External: | 126 | case audio::OutputState::External: |
2361 | 120 | std::cout << "AudioOutputObserver reports that output is now External." << std::endl; | 127 | std::cout << "AudioOutputObserver reports that output is now External." << std::endl; |
2362 | 121 | if (d->audio_output_state == audio::OutputState::Earpiece) | ||
2363 | 122 | pause_all_multimedia_sessions(); | ||
2364 | 123 | break; | 128 | break; |
2365 | 124 | } | 129 | } |
2366 | 125 | d->audio_output_state = state; | 130 | d->audio_output_state = state; |
2367 | 126 | }); | 131 | }); |
2368 | 127 | 132 | ||
2370 | 128 | d->call_monitor->on_change([this](CallMonitor::State state) { | 133 | d->call_monitor->on_call_state_changed().connect([this](media::telephony::CallMonitor::State state) |
2371 | 134 | { | ||
2372 | 129 | switch (state) { | 135 | switch (state) { |
2374 | 130 | case CallMonitor::OffHook: | 136 | case media::telephony::CallMonitor::State::OffHook: |
2375 | 131 | std::cout << "Got call started signal, pausing all multimedia sessions" << std::endl; | 137 | std::cout << "Got call started signal, pausing all multimedia sessions" << std::endl; |
2376 | 132 | pause_all_multimedia_sessions(); | 138 | pause_all_multimedia_sessions(); |
2377 | 133 | break; | 139 | break; |
2379 | 134 | case CallMonitor::OnHook: | 140 | case media::telephony::CallMonitor::State::OnHook: |
2380 | 135 | std::cout << "Got call ended signal, resuming paused multimedia sessions" << std::endl; | 141 | std::cout << "Got call ended signal, resuming paused multimedia sessions" << std::endl; |
2381 | 136 | // Don't auto-resume any paused video playback sessions | ||
2382 | 137 | resume_paused_multimedia_sessions(false); | 142 | resume_paused_multimedia_sessions(false); |
2383 | 138 | break; | 143 | break; |
2384 | 139 | } | 144 | } |
2385 | @@ -160,12 +165,15 @@ | |||
2386 | 160 | std::shared_ptr<media::Player> media::ServiceImplementation::create_session( | 165 | std::shared_ptr<media::Player> media::ServiceImplementation::create_session( |
2387 | 161 | const media::Player::Configuration& conf) | 166 | const media::Player::Configuration& conf) |
2388 | 162 | { | 167 | { |
2390 | 163 | auto player = std::make_shared<media::PlayerImplementation>(media::PlayerImplementation::Configuration | 168 | auto player = std::make_shared<media::PlayerImplementation<media::PlayerSkeleton>>(media::PlayerImplementation<media::PlayerSkeleton>::Configuration |
2391 | 164 | { | 169 | { |
2396 | 165 | conf.identity, | 170 | media::PlayerSkeleton::Configuration |
2397 | 166 | conf.bus, | 171 | { |
2398 | 167 | conf.session, | 172 | conf.bus, |
2399 | 168 | shared_from_this(), | 173 | conf.session, |
2400 | 174 | d->request_context_resolver, | ||
2401 | 175 | d->request_authenticator | ||
2402 | 176 | }, | ||
2403 | 169 | conf.key, | 177 | conf.key, |
2404 | 170 | d->client_death_observer, | 178 | d->client_death_observer, |
2405 | 171 | d->power_state_controller | 179 | d->power_state_controller |
2406 | @@ -181,11 +189,11 @@ | |||
2407 | 181 | // until all dispatches are done | 189 | // until all dispatches are done |
2408 | 182 | d->configuration.external_services.io_service.post([this, key]() | 190 | d->configuration.external_services.io_service.post([this, key]() |
2409 | 183 | { | 191 | { |
2411 | 184 | if (!has_player_for_key(key)) | 192 | if (!d->configuration.player_store->has_player_for_key(key)) |
2412 | 185 | return; | 193 | return; |
2413 | 186 | 194 | ||
2416 | 187 | if (player_for_key(key)->lifetime() == Player::Lifetime::normal) | 195 | if (d->configuration.player_store->player_for_key(key)->lifetime() == Player::Lifetime::normal) |
2417 | 188 | remove_player_for_key(key); | 196 | d->configuration.player_store->remove_player_for_key(key); |
2418 | 189 | }); | 197 | }); |
2419 | 190 | }); | 198 | }); |
2420 | 191 | 199 | ||
2421 | @@ -206,19 +214,19 @@ | |||
2422 | 206 | 214 | ||
2423 | 207 | void media::ServiceImplementation::pause_other_sessions(media::Player::PlayerKey key) | 215 | void media::ServiceImplementation::pause_other_sessions(media::Player::PlayerKey key) |
2424 | 208 | { | 216 | { |
2426 | 209 | if (not has_player_for_key(key)) | 217 | if (not d->configuration.player_store->has_player_for_key(key)) |
2427 | 210 | { | 218 | { |
2428 | 211 | cerr << "Could not find Player by key: " << key << endl; | 219 | cerr << "Could not find Player by key: " << key << endl; |
2429 | 212 | return; | 220 | return; |
2430 | 213 | } | 221 | } |
2431 | 214 | 222 | ||
2433 | 215 | auto current_player = player_for_key(key); | 223 | auto current_player = d->configuration.player_store->player_for_key(key); |
2434 | 216 | 224 | ||
2435 | 217 | // We immediately make the player known as new current player. | 225 | // We immediately make the player known as new current player. |
2436 | 218 | if (current_player->audio_stream_role() == media::Player::multimedia) | 226 | if (current_player->audio_stream_role() == media::Player::multimedia) |
2438 | 219 | set_current_player_for_key(key); | 227 | d->configuration.player_store->set_current_player_for_key(key); |
2439 | 220 | 228 | ||
2441 | 221 | enumerate_players([current_player, key](const media::Player::PlayerKey& other_key, const std::shared_ptr<media::Player>& other_player) | 229 | d->configuration.player_store->enumerate_players([current_player, key](const media::Player::PlayerKey& other_key, const std::shared_ptr<media::Player>& other_player) |
2442 | 222 | { | 230 | { |
2443 | 223 | // Only pause a Player if all of the following criteria are met: | 231 | // Only pause a Player if all of the following criteria are met: |
2444 | 224 | // 1) currently playing | 232 | // 1) currently playing |
2445 | @@ -238,7 +246,7 @@ | |||
2446 | 238 | 246 | ||
2447 | 239 | void media::ServiceImplementation::pause_all_multimedia_sessions() | 247 | void media::ServiceImplementation::pause_all_multimedia_sessions() |
2448 | 240 | { | 248 | { |
2450 | 241 | enumerate_players([this](const media::Player::PlayerKey& key, const std::shared_ptr<media::Player>& player) | 249 | d->configuration.player_store->enumerate_players([this](const media::Player::PlayerKey& key, const std::shared_ptr<media::Player>& player) |
2451 | 242 | { | 250 | { |
2452 | 243 | if (player->playback_status() == Player::playing | 251 | if (player->playback_status() == Player::playing |
2453 | 244 | && player->audio_stream_role() == media::Player::multimedia) | 252 | && player->audio_stream_role() == media::Player::multimedia) |
2454 | @@ -253,7 +261,7 @@ | |||
2455 | 253 | void media::ServiceImplementation::resume_paused_multimedia_sessions(bool resume_video_sessions) | 261 | void media::ServiceImplementation::resume_paused_multimedia_sessions(bool resume_video_sessions) |
2456 | 254 | { | 262 | { |
2457 | 255 | std::for_each(d->paused_sessions.begin(), d->paused_sessions.end(), [this, resume_video_sessions](const media::Player::PlayerKey& key) { | 263 | std::for_each(d->paused_sessions.begin(), d->paused_sessions.end(), [this, resume_video_sessions](const media::Player::PlayerKey& key) { |
2459 | 256 | auto player = player_for_key(key); | 264 | auto player = d->configuration.player_store->player_for_key(key); |
2460 | 257 | // Only resume video playback if explicitly desired | 265 | // Only resume video playback if explicitly desired |
2461 | 258 | if (resume_video_sessions || player->is_audio_source()) | 266 | if (resume_video_sessions || player->is_audio_source()) |
2462 | 259 | player->play(); | 267 | player->play(); |
2463 | @@ -266,10 +274,10 @@ | |||
2464 | 266 | 274 | ||
2465 | 267 | void media::ServiceImplementation::resume_multimedia_session() | 275 | void media::ServiceImplementation::resume_multimedia_session() |
2466 | 268 | { | 276 | { |
2468 | 269 | if (not has_player_for_key(d->resume_key)) | 277 | if (not d->configuration.player_store->has_player_for_key(d->resume_key)) |
2469 | 270 | return; | 278 | return; |
2470 | 271 | 279 | ||
2472 | 272 | auto player = player_for_key(d->resume_key); | 280 | auto player = d->configuration.player_store->player_for_key(d->resume_key); |
2473 | 273 | 281 | ||
2474 | 274 | if (player->playback_status() == Player::paused) | 282 | if (player->playback_status() == Player::paused) |
2475 | 275 | { | 283 | { |
2476 | 276 | 284 | ||
2477 | === modified file 'src/core/media/service_implementation.h' | |||
2478 | --- src/core/media/service_implementation.h 2015-03-16 15:38:27 +0000 | |||
2479 | +++ src/core/media/service_implementation.h 2015-03-16 15:38:27 +0000 | |||
2480 | @@ -30,12 +30,13 @@ | |||
2481 | 30 | { | 30 | { |
2482 | 31 | class Player; | 31 | class Player; |
2483 | 32 | 32 | ||
2485 | 33 | class ServiceImplementation : public ServiceSkeleton | 33 | class ServiceImplementation : public Service |
2486 | 34 | { | 34 | { |
2487 | 35 | public: | 35 | public: |
2488 | 36 | // All creation time arguments go here. | 36 | // All creation time arguments go here. |
2489 | 37 | struct Configuration | 37 | struct Configuration |
2490 | 38 | { | 38 | { |
2491 | 39 | KeyedPlayerStore::Ptr player_store; | ||
2492 | 39 | helper::ExternalServices& external_services; | 40 | helper::ExternalServices& external_services; |
2493 | 40 | }; | 41 | }; |
2494 | 41 | 42 | ||
2495 | 42 | 43 | ||
2496 | === modified file 'src/core/media/service_skeleton.cpp' | |||
2497 | --- src/core/media/service_skeleton.cpp 2014-11-18 20:29:26 +0000 | |||
2498 | +++ src/core/media/service_skeleton.cpp 2015-03-16 15:38:27 +0000 | |||
2499 | @@ -19,8 +19,6 @@ | |||
2500 | 19 | 19 | ||
2501 | 20 | #include "service_skeleton.h" | 20 | #include "service_skeleton.h" |
2502 | 21 | 21 | ||
2503 | 22 | #include "apparmor.h" | ||
2504 | 23 | |||
2505 | 24 | #include "mpris/media_player2.h" | 22 | #include "mpris/media_player2.h" |
2506 | 25 | #include "mpris/metadata.h" | 23 | #include "mpris/metadata.h" |
2507 | 26 | #include "mpris/player.h" | 24 | #include "mpris/player.h" |
2508 | @@ -51,12 +49,12 @@ | |||
2509 | 51 | 49 | ||
2510 | 52 | struct media::ServiceSkeleton::Private | 50 | struct media::ServiceSkeleton::Private |
2511 | 53 | { | 51 | { |
2513 | 54 | Private(media::ServiceSkeleton* impl, const media::CoverArtResolver& resolver) | 52 | Private(media::ServiceSkeleton* impl, const ServiceSkeleton::Configuration& config) |
2514 | 55 | : impl(impl), | 53 | : impl(impl), |
2515 | 56 | object(impl->access_service()->add_object_for_path( | 54 | object(impl->access_service()->add_object_for_path( |
2519 | 57 | dbus::traits::Service<media::Service>::object_path())), | 55 | dbus::traits::Service<media::Service>::object_path())), |
2520 | 58 | dbus_stub(impl->access_bus()), | 56 | exported(impl->access_bus(), config.cover_art_resolver), |
2521 | 59 | exported(impl->access_bus(), resolver) | 57 | configuration(config) |
2522 | 60 | { | 58 | { |
2523 | 61 | object->install_method_handler<mpris::Service::CreateSession>( | 59 | object->install_method_handler<mpris::Service::CreateSession>( |
2524 | 62 | std::bind( | 60 | std::bind( |
2525 | @@ -99,129 +97,71 @@ | |||
2526 | 99 | dbus::types::ObjectPath op{session_info.first}; | 97 | dbus::types::ObjectPath op{session_info.first}; |
2527 | 100 | media::Player::PlayerKey key{session_info.second}; | 98 | media::Player::PlayerKey key{session_info.second}; |
2528 | 101 | 99 | ||
2541 | 102 | dbus_stub.get_connection_app_armor_security_async(msg->sender(), [this, msg, op, key](const std::string& profile) | 100 | media::Player::Configuration config |
2542 | 103 | { | 101 | { |
2543 | 104 | media::Player::Configuration config | 102 | key, |
2544 | 105 | { | 103 | impl->access_bus(), |
2545 | 106 | profile, | 104 | impl->access_service()->add_object_for_path(op) |
2546 | 107 | key, | 105 | }; |
2547 | 108 | impl->access_bus(), | 106 | |
2548 | 109 | impl->access_service()->add_object_for_path(op) | 107 | try |
2549 | 110 | }; | 108 | { |
2550 | 111 | 109 | configuration.player_store->add_player_for_key(key, impl->create_session(config)); | |
2551 | 112 | try | 110 | auto reply = dbus::Message::make_method_return(msg); |
2552 | 113 | { | 111 | reply->writer() << op; |
2553 | 112 | |||
2554 | 113 | impl->access_bus()->send(reply); | ||
2555 | 114 | } catch(const std::runtime_error& e) | ||
2556 | 115 | { | ||
2557 | 116 | auto reply = dbus::Message::make_error( | ||
2558 | 117 | msg, | ||
2559 | 118 | mpris::Service::Errors::CreatingSession::name(), | ||
2560 | 119 | e.what()); | ||
2561 | 120 | impl->access_bus()->send(reply); | ||
2562 | 121 | } | ||
2563 | 122 | } | ||
2564 | 123 | |||
2565 | 124 | void handle_create_fixed_session(const core::dbus::Message::Ptr& msg) | ||
2566 | 125 | { | ||
2567 | 126 | try | ||
2568 | 127 | { | ||
2569 | 128 | std::string name; | ||
2570 | 129 | msg->reader() >> name; | ||
2571 | 130 | |||
2572 | 131 | if (named_player_map.count(name) == 0) { | ||
2573 | 132 | // Create new session | ||
2574 | 133 | auto session_info = create_session_info(); | ||
2575 | 134 | |||
2576 | 135 | dbus::types::ObjectPath op{session_info.first}; | ||
2577 | 136 | media::Player::PlayerKey key{session_info.second}; | ||
2578 | 137 | |||
2579 | 138 | media::Player::Configuration config | ||
2580 | 139 | { | ||
2581 | 140 | key, | ||
2582 | 141 | impl->access_bus(), | ||
2583 | 142 | impl->access_service()->add_object_for_path(op) | ||
2584 | 143 | }; | ||
2585 | 144 | |||
2586 | 114 | auto session = impl->create_session(config); | 145 | auto session = impl->create_session(config); |
2595 | 115 | 146 | session->lifetime().set(media::Player::Lifetime::resumable); | |
2596 | 116 | bool inserted = false; | 147 | |
2597 | 117 | std::tie(std::ignore, inserted) | 148 | configuration.player_store->add_player_for_key(key, session); |
2598 | 118 | = session_store.insert(std::make_pair(key, session)); | 149 | |
2599 | 119 | 150 | ||
2600 | 120 | if (!inserted) | 151 | named_player_map.insert(std::make_pair(name, key)); |
2593 | 121 | throw std::runtime_error("Problem persisting session in session store."); | ||
2594 | 122 | |||
2601 | 123 | 152 | ||
2602 | 124 | auto reply = dbus::Message::make_method_return(msg); | 153 | auto reply = dbus::Message::make_method_return(msg); |
2603 | 125 | reply->writer() << op; | 154 | reply->writer() << op; |
2604 | 126 | 155 | ||
2605 | 127 | impl->access_bus()->send(reply); | 156 | impl->access_bus()->send(reply); |
2700 | 128 | } catch(const std::runtime_error& e) | 157 | } |
2701 | 129 | { | 158 | else { |
2702 | 130 | auto reply = dbus::Message::make_error( | 159 | // Resume previous session |
2703 | 131 | msg, | 160 | auto key = named_player_map.at(name); |
2704 | 132 | mpris::Service::Errors::CreatingSession::name(), | 161 | if (not configuration.player_store->has_player_for_key(key)) { |
2611 | 133 | e.what()); | ||
2612 | 134 | impl->access_bus()->send(reply); | ||
2613 | 135 | } | ||
2614 | 136 | }); | ||
2615 | 137 | } | ||
2616 | 138 | |||
2617 | 139 | void handle_create_fixed_session(const core::dbus::Message::Ptr& msg) | ||
2618 | 140 | { | ||
2619 | 141 | dbus_stub.get_connection_app_armor_security_async(msg->sender(), [this, msg](const std::string& profile) | ||
2620 | 142 | { | ||
2621 | 143 | try | ||
2622 | 144 | { | ||
2623 | 145 | std::string name; | ||
2624 | 146 | msg->reader() >> name; | ||
2625 | 147 | |||
2626 | 148 | if (fixed_session_store.count(name) == 0) { | ||
2627 | 149 | // Create new session | ||
2628 | 150 | auto session_info = create_session_info(); | ||
2629 | 151 | |||
2630 | 152 | dbus::types::ObjectPath op{session_info.first}; | ||
2631 | 153 | media::Player::PlayerKey key{session_info.second}; | ||
2632 | 154 | |||
2633 | 155 | media::Player::Configuration config | ||
2634 | 156 | { | ||
2635 | 157 | profile, | ||
2636 | 158 | key, | ||
2637 | 159 | impl->access_bus(), | ||
2638 | 160 | impl->access_service()->add_object_for_path(op) | ||
2639 | 161 | }; | ||
2640 | 162 | |||
2641 | 163 | auto session = impl->create_session(config); | ||
2642 | 164 | session->lifetime().set(media::Player::Lifetime::resumable); | ||
2643 | 165 | |||
2644 | 166 | bool inserted = false; | ||
2645 | 167 | std::tie(std::ignore, inserted) | ||
2646 | 168 | = session_store.insert(std::make_pair(key, session)); | ||
2647 | 169 | |||
2648 | 170 | if (!inserted) | ||
2649 | 171 | throw std::runtime_error("Problem persisting session in session store."); | ||
2650 | 172 | |||
2651 | 173 | fixed_session_store.insert(std::make_pair(name, key)); | ||
2652 | 174 | |||
2653 | 175 | auto reply = dbus::Message::make_method_return(msg); | ||
2654 | 176 | reply->writer() << op; | ||
2655 | 177 | |||
2656 | 178 | impl->access_bus()->send(reply); | ||
2657 | 179 | } | ||
2658 | 180 | else { | ||
2659 | 181 | // Resume previous session | ||
2660 | 182 | auto key = fixed_session_store[name]; | ||
2661 | 183 | if (session_store.count(key) == 0) { | ||
2662 | 184 | auto reply = dbus::Message::make_error( | ||
2663 | 185 | msg, | ||
2664 | 186 | mpris::Service::Errors::CreatingFixedSession::name(), | ||
2665 | 187 | "Unable to locate player session"); | ||
2666 | 188 | impl->access_bus()->send(reply); | ||
2667 | 189 | return; | ||
2668 | 190 | } | ||
2669 | 191 | |||
2670 | 192 | std::stringstream ss; | ||
2671 | 193 | ss << "/core/ubuntu/media/Service/sessions/" << key; | ||
2672 | 194 | dbus::types::ObjectPath op{ss.str()}; | ||
2673 | 195 | |||
2674 | 196 | auto reply = dbus::Message::make_method_return(msg); | ||
2675 | 197 | reply->writer() << op; | ||
2676 | 198 | |||
2677 | 199 | impl->access_bus()->send(reply); | ||
2678 | 200 | } | ||
2679 | 201 | } catch(const std::runtime_error& e) | ||
2680 | 202 | { | ||
2681 | 203 | auto reply = dbus::Message::make_error( | ||
2682 | 204 | msg, | ||
2683 | 205 | mpris::Service::Errors::CreatingSession::name(), | ||
2684 | 206 | e.what()); | ||
2685 | 207 | impl->access_bus()->send(reply); | ||
2686 | 208 | } | ||
2687 | 209 | }); | ||
2688 | 210 | } | ||
2689 | 211 | |||
2690 | 212 | void handle_resume_session(const core::dbus::Message::Ptr& msg) | ||
2691 | 213 | { | ||
2692 | 214 | dbus_stub.get_connection_app_armor_security_async(msg->sender(), [this, msg](const std::string&) | ||
2693 | 215 | { | ||
2694 | 216 | try | ||
2695 | 217 | { | ||
2696 | 218 | Player::PlayerKey key; | ||
2697 | 219 | msg->reader() >> key; | ||
2698 | 220 | |||
2699 | 221 | if (session_store.count(key) == 0) { | ||
2705 | 222 | auto reply = dbus::Message::make_error( | 162 | auto reply = dbus::Message::make_error( |
2706 | 223 | msg, | 163 | msg, |
2708 | 224 | mpris::Service::Errors::ResumingSession::name(), | 164 | mpris::Service::Errors::CreatingFixedSession::name(), |
2709 | 225 | "Unable to locate player session"); | 165 | "Unable to locate player session"); |
2710 | 226 | impl->access_bus()->send(reply); | 166 | impl->access_bus()->send(reply); |
2711 | 227 | return; | 167 | return; |
2712 | @@ -235,15 +175,49 @@ | |||
2713 | 235 | reply->writer() << op; | 175 | reply->writer() << op; |
2714 | 236 | 176 | ||
2715 | 237 | impl->access_bus()->send(reply); | 177 | impl->access_bus()->send(reply); |
2718 | 238 | } catch(const std::runtime_error& e) | 178 | } |
2719 | 239 | { | 179 | } catch(const std::runtime_error& e) |
2720 | 180 | { | ||
2721 | 181 | auto reply = dbus::Message::make_error( | ||
2722 | 182 | msg, | ||
2723 | 183 | mpris::Service::Errors::CreatingSession::name(), | ||
2724 | 184 | e.what()); | ||
2725 | 185 | impl->access_bus()->send(reply); | ||
2726 | 186 | } | ||
2727 | 187 | } | ||
2728 | 188 | |||
2729 | 189 | void handle_resume_session(const core::dbus::Message::Ptr& msg) | ||
2730 | 190 | { | ||
2731 | 191 | try | ||
2732 | 192 | { | ||
2733 | 193 | Player::PlayerKey key; | ||
2734 | 194 | msg->reader() >> key; | ||
2735 | 195 | |||
2736 | 196 | if (not configuration.player_store->has_player_for_key(key)) { | ||
2737 | 240 | auto reply = dbus::Message::make_error( | 197 | auto reply = dbus::Message::make_error( |
2738 | 241 | msg, | 198 | msg, |
2741 | 242 | mpris::Service::Errors::CreatingSession::name(), | 199 | mpris::Service::Errors::ResumingSession::name(), |
2742 | 243 | e.what()); | 200 | "Unable to locate player session"); |
2743 | 244 | impl->access_bus()->send(reply); | 201 | impl->access_bus()->send(reply); |
2744 | 202 | return; | ||
2745 | 245 | } | 203 | } |
2747 | 246 | }); | 204 | |
2748 | 205 | std::stringstream ss; | ||
2749 | 206 | ss << "/core/ubuntu/media/Service/sessions/" << key; | ||
2750 | 207 | dbus::types::ObjectPath op{ss.str()}; | ||
2751 | 208 | |||
2752 | 209 | auto reply = dbus::Message::make_method_return(msg); | ||
2753 | 210 | reply->writer() << op; | ||
2754 | 211 | |||
2755 | 212 | impl->access_bus()->send(reply); | ||
2756 | 213 | } catch(const std::runtime_error& e) | ||
2757 | 214 | { | ||
2758 | 215 | auto reply = dbus::Message::make_error( | ||
2759 | 216 | msg, | ||
2760 | 217 | mpris::Service::Errors::CreatingSession::name(), | ||
2761 | 218 | e.what()); | ||
2762 | 219 | impl->access_bus()->send(reply); | ||
2763 | 220 | } | ||
2764 | 247 | } | 221 | } |
2765 | 248 | 222 | ||
2766 | 249 | void handle_pause_other_sessions(const core::dbus::Message::Ptr& msg) | 223 | void handle_pause_other_sessions(const core::dbus::Message::Ptr& msg) |
2767 | @@ -260,11 +234,10 @@ | |||
2768 | 260 | media::ServiceSkeleton* impl; | 234 | media::ServiceSkeleton* impl; |
2769 | 261 | dbus::Object::Ptr object; | 235 | dbus::Object::Ptr object; |
2770 | 262 | 236 | ||
2776 | 263 | // We query the apparmor profile to obtain an identity for players. | 237 | // We remember all our creation time arguments. |
2777 | 264 | org::freedesktop::dbus::DBus::Stub dbus_stub; | 238 | ServiceSkeleton::Configuration configuration; |
2778 | 265 | // We track all running player instances. | 239 | // We map named/fixed player instances to their respective keys. |
2779 | 266 | std::map<media::Player::PlayerKey, std::shared_ptr<media::Player>> session_store; | 240 | std::map<std::string, media::Player::PlayerKey> named_player_map; |
2775 | 267 | std::map<std::string, media::Player::PlayerKey> fixed_session_store; | ||
2780 | 268 | // We expose the entire service as an MPRIS player. | 241 | // We expose the entire service as an MPRIS player. |
2781 | 269 | struct Exported | 242 | struct Exported |
2782 | 270 | { | 243 | { |
2783 | @@ -498,7 +471,7 @@ | |||
2784 | 498 | mpris::Player::Skeleton player; | 471 | mpris::Player::Skeleton player; |
2785 | 499 | mpris::Playlists::Skeleton playlists; | 472 | mpris::Playlists::Skeleton playlists; |
2786 | 500 | 473 | ||
2788 | 501 | // Helper to resolve (title, artist, album) tuples to cover art. | 474 | // The CoverArtResolver used by the exported player. |
2789 | 502 | media::CoverArtResolver cover_art_resolver; | 475 | media::CoverArtResolver cover_art_resolver; |
2790 | 503 | // The actual player instance. | 476 | // The actual player instance. |
2791 | 504 | std::weak_ptr<media::Player> current_player; | 477 | std::weak_ptr<media::Player> current_player; |
2792 | @@ -533,9 +506,9 @@ | |||
2793 | 533 | } exported; | 506 | } exported; |
2794 | 534 | }; | 507 | }; |
2795 | 535 | 508 | ||
2797 | 536 | media::ServiceSkeleton::ServiceSkeleton(const media::CoverArtResolver& resolver) | 509 | media::ServiceSkeleton::ServiceSkeleton(const Configuration& configuration) |
2798 | 537 | : dbus::Skeleton<media::Service>(the_session_bus()), | 510 | : dbus::Skeleton<media::Service>(the_session_bus()), |
2800 | 538 | d(new Private(this, resolver)) | 511 | d(new Private(this, configuration)) |
2801 | 539 | { | 512 | { |
2802 | 540 | } | 513 | } |
2803 | 541 | 514 | ||
2804 | @@ -543,46 +516,24 @@ | |||
2805 | 543 | { | 516 | { |
2806 | 544 | } | 517 | } |
2807 | 545 | 518 | ||
2848 | 546 | bool media::ServiceSkeleton::has_player_for_key(const media::Player::PlayerKey& key) const | 519 | std::shared_ptr<media::Player> media::ServiceSkeleton::create_session(const media::Player::Configuration& config) |
2849 | 547 | { | 520 | { |
2850 | 548 | return d->session_store.count(key) > 0; | 521 | return d->configuration.impl->create_session(config); |
2851 | 549 | } | 522 | } |
2852 | 550 | 523 | ||
2853 | 551 | std::shared_ptr<media::Player> media::ServiceSkeleton::player_for_key(const media::Player::PlayerKey& key) const | 524 | std::shared_ptr<media::Player> media::ServiceSkeleton::create_fixed_session(const std::string& name, const media::Player::Configuration&config) |
2854 | 552 | { | 525 | { |
2855 | 553 | return d->session_store.at(key); | 526 | return d->configuration.impl->create_fixed_session(name, config); |
2856 | 554 | } | 527 | } |
2857 | 555 | 528 | ||
2858 | 556 | void media::ServiceSkeleton::enumerate_players(const media::ServiceSkeleton::PlayerEnumerator& enumerator) const | 529 | std::shared_ptr<media::Player> media::ServiceSkeleton::resume_session(media::Player::PlayerKey key) |
2859 | 557 | { | 530 | { |
2860 | 558 | for (const auto& pair : d->session_store) | 531 | return d->configuration.impl->resume_session(key); |
2861 | 559 | enumerator(pair.first, pair.second); | 532 | } |
2862 | 560 | } | 533 | |
2863 | 561 | 534 | void media::ServiceSkeleton::pause_other_sessions(media::Player::PlayerKey key) | |
2864 | 562 | void media::ServiceSkeleton::set_current_player_for_key(const media::Player::PlayerKey& key) | 535 | { |
2865 | 563 | { | 536 | d->configuration.impl->pause_other_sessions(key); |
2826 | 564 | if (not has_player_for_key(key)) | ||
2827 | 565 | return; | ||
2828 | 566 | |||
2829 | 567 | d->exported.set_current_player(player_for_key(key)); | ||
2830 | 568 | } | ||
2831 | 569 | |||
2832 | 570 | void media::ServiceSkeleton::remove_player_for_key(const media::Player::PlayerKey& key) | ||
2833 | 571 | { | ||
2834 | 572 | if (not has_player_for_key(key)) | ||
2835 | 573 | return; | ||
2836 | 574 | |||
2837 | 575 | auto player = player_for_key(key); | ||
2838 | 576 | |||
2839 | 577 | d->session_store.erase(key); | ||
2840 | 578 | d->exported.unset_if_current(player); | ||
2841 | 579 | // All non-durable fixed sessions are also removed | ||
2842 | 580 | for (auto it: d->fixed_session_store) { | ||
2843 | 581 | if (it.second == key) { | ||
2844 | 582 | d->fixed_session_store.erase(it.first); | ||
2845 | 583 | break; | ||
2846 | 584 | } | ||
2847 | 585 | } | ||
2866 | 586 | } | 537 | } |
2867 | 587 | 538 | ||
2868 | 588 | void media::ServiceSkeleton::run() | 539 | void media::ServiceSkeleton::run() |
2869 | 589 | 540 | ||
2870 | === modified file 'src/core/media/service_skeleton.h' | |||
2871 | --- src/core/media/service_skeleton.h 2014-09-09 21:27:29 +0000 | |||
2872 | +++ src/core/media/service_skeleton.h 2015-03-16 15:38:27 +0000 | |||
2873 | @@ -22,6 +22,7 @@ | |||
2874 | 22 | #include <core/media/service.h> | 22 | #include <core/media/service.h> |
2875 | 23 | 23 | ||
2876 | 24 | #include "cover_art_resolver.h" | 24 | #include "cover_art_resolver.h" |
2877 | 25 | #include "keyed_player_store.h" | ||
2878 | 25 | #include "service_traits.h" | 26 | #include "service_traits.h" |
2879 | 26 | 27 | ||
2880 | 27 | #include <core/dbus/skeleton.h> | 28 | #include <core/dbus/skeleton.h> |
2881 | @@ -37,34 +38,22 @@ | |||
2882 | 37 | class ServiceSkeleton : public core::dbus::Skeleton<core::ubuntu::media::Service> | 38 | class ServiceSkeleton : public core::dbus::Skeleton<core::ubuntu::media::Service> |
2883 | 38 | { | 39 | { |
2884 | 39 | public: | 40 | public: |
2895 | 40 | // Functor for enumerating all known (key, player) pairs. | 41 | // Creation time arguments go here. |
2896 | 41 | typedef std::function | 42 | struct Configuration |
2897 | 42 | < | 43 | { |
2898 | 43 | void( | 44 | std::shared_ptr<Service> impl; |
2899 | 44 | // The key of the player. | 45 | KeyedPlayerStore::Ptr player_store; |
2900 | 45 | const core::ubuntu::media::Player::PlayerKey&, | 46 | CoverArtResolver cover_art_resolver; |
2901 | 46 | // The actual player instance. | 47 | }; |
2892 | 47 | const std::shared_ptr<core::ubuntu::media::Player>& | ||
2893 | 48 | ) | ||
2894 | 49 | > PlayerEnumerator; | ||
2902 | 50 | 48 | ||
2904 | 51 | ServiceSkeleton(const CoverArtResolver& cover_art_resolver = always_missing_cover_art_resolver()); | 49 | ServiceSkeleton(const Configuration& configuration); |
2905 | 52 | ~ServiceSkeleton(); | 50 | ~ServiceSkeleton(); |
2906 | 53 | 51 | ||
2921 | 54 | // We keep track of all known player sessions here and render them accessible via | 52 | // From media::Service |
2922 | 55 | // the key. All of these functions are thread-safe but not reentrant. | 53 | std::shared_ptr<Player> create_session(const Player::Configuration&); |
2923 | 56 | // Returns true iff a player is known for the given key. | 54 | std::shared_ptr<Player> create_fixed_session(const std::string& name, const Player::Configuration&); |
2924 | 57 | bool has_player_for_key(const Player::PlayerKey& key) const; | 55 | std::shared_ptr<Player> resume_session(Player::PlayerKey); |
2925 | 58 | // Returns the player for the given key or throws std::out_of_range if no player is known | 56 | void pause_other_sessions(Player::PlayerKey key); |
2912 | 59 | // for the given key. | ||
2913 | 60 | std::shared_ptr<Player> player_for_key(const Player::PlayerKey& key) const; | ||
2914 | 61 | // Enumerates all known players and invokes the given enumerator for each | ||
2915 | 62 | // (key, player) pair. | ||
2916 | 63 | void enumerate_players(const PlayerEnumerator& enumerator) const; | ||
2917 | 64 | // Removes the player for the given key, and unsets it if it is the current one. | ||
2918 | 65 | void remove_player_for_key(const Player::PlayerKey& key); | ||
2919 | 66 | // Makes the player known under the given key current. | ||
2920 | 67 | void set_current_player_for_key(const Player::PlayerKey& key); | ||
2926 | 68 | 57 | ||
2927 | 69 | void run(); | 58 | void run(); |
2928 | 70 | void stop(); | 59 | void stop(); |
2929 | 71 | 60 | ||
2930 | === renamed directory 'src/core/media/call-monitor' => 'src/core/media/telephony' | |||
2931 | === modified file 'src/core/media/telephony/call_monitor.cpp' | |||
2932 | --- src/core/media/call-monitor/call_monitor.cpp 2015-01-12 21:35:36 +0000 | |||
2933 | +++ src/core/media/telephony/call_monitor.cpp 2015-03-16 15:38:27 +0000 | |||
2934 | @@ -29,8 +29,12 @@ | |||
2935 | 29 | #include <list> | 29 | #include <list> |
2936 | 30 | #include <mutex> | 30 | #include <mutex> |
2937 | 31 | 31 | ||
2938 | 32 | namespace media = core::ubuntu::media; | ||
2939 | 32 | 33 | ||
2941 | 33 | namespace { | 34 | namespace |
2942 | 35 | { | ||
2943 | 36 | namespace impl | ||
2944 | 37 | { | ||
2945 | 34 | class TelepathyCallMonitor : public QObject | 38 | class TelepathyCallMonitor : public QObject |
2946 | 35 | { | 39 | { |
2947 | 36 | Q_OBJECT | 40 | Q_OBJECT |
2948 | @@ -73,7 +77,7 @@ | |||
2949 | 73 | } | 77 | } |
2950 | 74 | } | 78 | } |
2951 | 75 | 79 | ||
2953 | 76 | void on_change(const std::function<void(CallMonitor::State)>& func) { | 80 | void on_change(const std::function<void(media::telephony::CallMonitor::State)>& func) { |
2954 | 77 | std::lock_guard<std::mutex> l(cb_lock); | 81 | std::lock_guard<std::mutex> l(cb_lock); |
2955 | 78 | cb = func; | 82 | cb = func; |
2956 | 79 | } | 83 | } |
2957 | @@ -131,19 +135,19 @@ | |||
2958 | 131 | { | 135 | { |
2959 | 132 | std::lock_guard<std::mutex> l(cb_lock); | 136 | std::lock_guard<std::mutex> l(cb_lock); |
2960 | 133 | if (cb) | 137 | if (cb) |
2962 | 134 | cb(CallMonitor::OffHook); | 138 | cb(media::telephony::CallMonitor::State::OffHook); |
2963 | 135 | } | 139 | } |
2964 | 136 | 140 | ||
2965 | 137 | void onHook() | 141 | void onHook() |
2966 | 138 | { | 142 | { |
2967 | 139 | std::lock_guard<std::mutex> l(cb_lock); | 143 | std::lock_guard<std::mutex> l(cb_lock); |
2968 | 140 | if (cb) | 144 | if (cb) |
2970 | 141 | cb(CallMonitor::OnHook); | 145 | cb(media::telephony::CallMonitor::State::OnHook); |
2971 | 142 | } | 146 | } |
2972 | 143 | 147 | ||
2973 | 144 | private: | 148 | private: |
2974 | 145 | std::mutex cb_lock; | 149 | std::mutex cb_lock; |
2976 | 146 | std::function<void (CallMonitor::State)> cb; | 150 | std::function<void (media::telephony::CallMonitor::State)> cb; |
2977 | 147 | Tp::AccountManagerPtr mAccountManager; | 151 | Tp::AccountManagerPtr mAccountManager; |
2978 | 148 | std::list<TelepathyCallMonitor*> mCallMonitors; | 152 | std::list<TelepathyCallMonitor*> mCallMonitors; |
2979 | 149 | 153 | ||
2980 | @@ -159,63 +163,78 @@ | |||
2981 | 159 | mCallMonitors.push_back(tcm); | 163 | mCallMonitors.push_back(tcm); |
2982 | 160 | } | 164 | } |
2983 | 161 | }; | 165 | }; |
2984 | 162 | } | ||
2985 | 163 | 166 | ||
2987 | 164 | class CallMonitorPrivate | 167 | struct CallMonitor : public media::telephony::CallMonitor |
2988 | 165 | { | 168 | { |
2996 | 166 | public: | 169 | CallMonitor() : mBridge{nullptr} |
2997 | 167 | CallMonitorPrivate() { | 170 | { |
2998 | 168 | mBridge = nullptr; | 171 | try |
2999 | 169 | try { | 172 | { |
3000 | 170 | std::thread([this]() { | 173 | qt_world = std::move(std::thread([this]() |
3001 | 171 | qt::core::world::build_and_run(0, nullptr, [this]() { | 174 | { |
3002 | 172 | qt::core::world::enter_with_task([this]() { | 175 | qt::core::world::build_and_run(0, nullptr, [this]() |
3003 | 176 | { | ||
3004 | 177 | qt::core::world::enter_with_task([this]() | ||
3005 | 178 | { | ||
3006 | 173 | std::cout << "CallMonitor: Creating TelepathyBridge" << std::endl; | 179 | std::cout << "CallMonitor: Creating TelepathyBridge" << std::endl; |
3007 | 174 | mBridge = new TelepathyBridge(); | 180 | mBridge = new TelepathyBridge(); |
3008 | 175 | cv.notify_all(); | 181 | cv.notify_all(); |
3009 | 176 | }); | 182 | }); |
3010 | 177 | }); | 183 | }); |
3012 | 178 | }).detach(); | 184 | })); |
3013 | 179 | } catch(const std::system_error& error) { | 185 | } catch(const std::system_error& error) { |
3014 | 180 | std::cerr << "exception(std::system_error) in CallMonitor thread start" << error.what() << std::endl; | 186 | std::cerr << "exception(std::system_error) in CallMonitor thread start" << error.what() << std::endl; |
3015 | 181 | } catch(...) { | 187 | } catch(...) { |
3016 | 182 | std::cerr << "exception(...) in CallMonitor thread start" << std::endl; | 188 | std::cerr << "exception(...) in CallMonitor thread start" << std::endl; |
3017 | 183 | } | 189 | } |
3018 | 190 | |||
3019 | 184 | // Wait until telepathy bridge is set, so we can hook up the change signals | 191 | // Wait until telepathy bridge is set, so we can hook up the change signals |
3020 | 185 | std::unique_lock<std::mutex> lck(mtx); | 192 | std::unique_lock<std::mutex> lck(mtx); |
3021 | 186 | cv.wait_for(lck, std::chrono::seconds(3)); | 193 | cv.wait_for(lck, std::chrono::seconds(3)); |
3022 | 194 | |||
3023 | 195 | if (mBridge) | ||
3024 | 196 | { | ||
3025 | 197 | mBridge->on_change([this](CallMonitor::State state) | ||
3026 | 198 | { | ||
3027 | 199 | call_state_changed(state); | ||
3028 | 200 | }); | ||
3029 | 201 | } | ||
3030 | 187 | } | 202 | } |
3031 | 188 | 203 | ||
3033 | 189 | ~CallMonitorPrivate() { | 204 | ~CallMonitor() |
3034 | 205 | { | ||
3035 | 206 | // We first clean up the bridge instance. | ||
3036 | 207 | qt::core::world::enter_with_task([this]() | ||
3037 | 208 | { | ||
3038 | 209 | delete mBridge; | ||
3039 | 210 | }).get(); | ||
3040 | 211 | |||
3041 | 212 | // We then request destruction of the qt world. | ||
3042 | 190 | qt::core::world::destroy(); | 213 | qt::core::world::destroy(); |
3043 | 214 | |||
3044 | 215 | // Before we finally join the worker. | ||
3045 | 216 | if (qt_world.joinable()) | ||
3046 | 217 | qt_world.join(); | ||
3047 | 218 | } | ||
3048 | 219 | |||
3049 | 220 | const core::Signal<media::telephony::CallMonitor::State>& on_call_state_changed() const | ||
3050 | 221 | { | ||
3051 | 222 | return call_state_changed; | ||
3052 | 191 | } | 223 | } |
3053 | 192 | 224 | ||
3054 | 193 | TelepathyBridge *mBridge; | 225 | TelepathyBridge *mBridge; |
3055 | 226 | core::Signal<media::telephony::CallMonitor::State> call_state_changed; | ||
3056 | 194 | 227 | ||
3058 | 195 | private: | 228 | std::thread qt_world; |
3059 | 196 | std::mutex mtx; | 229 | std::mutex mtx; |
3060 | 197 | std::condition_variable cv; | 230 | std::condition_variable cv; |
3061 | 198 | }; | 231 | }; |
3082 | 199 | 232 | } | |
3083 | 200 | 233 | } | |
3084 | 201 | CallMonitor::CallMonitor(): | 234 | |
3085 | 202 | d(new CallMonitorPrivate) | 235 | media::telephony::CallMonitor::Ptr media::telephony::make_platform_default_call_monitor() |
3086 | 203 | { | 236 | { |
3087 | 204 | } | 237 | return std::make_shared<impl::CallMonitor>(); |
3068 | 205 | |||
3069 | 206 | CallMonitor::~CallMonitor() | ||
3070 | 207 | { | ||
3071 | 208 | delete d->mBridge; | ||
3072 | 209 | delete d; | ||
3073 | 210 | } | ||
3074 | 211 | |||
3075 | 212 | void CallMonitor::on_change(const std::function<void(CallMonitor::State)>& func) | ||
3076 | 213 | { | ||
3077 | 214 | if (d->mBridge != nullptr) { | ||
3078 | 215 | std::cout << "CallMonitor: Setting up callback for TelepathyBridge on_change" << std::endl; | ||
3079 | 216 | d->mBridge->on_change(func); | ||
3080 | 217 | } else | ||
3081 | 218 | std::cerr << "TelepathyBridge: Failed to hook on_change signal, bridge not yet set" << std::endl; | ||
3088 | 219 | } | 238 | } |
3089 | 220 | 239 | ||
3090 | 221 | #include "call_monitor.moc" | 240 | #include "call_monitor.moc" |
3091 | 222 | 241 | ||
3092 | === modified file 'src/core/media/telephony/call_monitor.h' | |||
3093 | --- src/core/media/call-monitor/call_monitor.h 2014-10-31 07:49:33 +0000 | |||
3094 | +++ src/core/media/telephony/call_monitor.h 2015-03-16 15:38:27 +0000 | |||
3095 | @@ -17,25 +17,50 @@ | |||
3096 | 17 | */ | 17 | */ |
3097 | 18 | 18 | ||
3098 | 19 | 19 | ||
3101 | 20 | #ifndef CALLMONITOR_H | 20 | #ifndef CORE_UBUNTU_MEDIA_TELEPHONY_CALL_MONITOR_H_ |
3102 | 21 | #define CALLMONITOR_H | 21 | #define CORE_UBUNTU_MEDIA_TELEPHONY_CALL_MONITOR_H_ |
3103 | 22 | |||
3104 | 23 | #include <core/signal.h> | ||
3105 | 22 | 24 | ||
3106 | 23 | #include <functional> | 25 | #include <functional> |
3122 | 24 | 26 | #include <memory> | |
3123 | 25 | class CallMonitorPrivate; | 27 | |
3124 | 26 | 28 | namespace core | |
3125 | 27 | class CallMonitor | 29 | { |
3126 | 28 | { | 30 | namespace ubuntu |
3127 | 29 | public: | 31 | { |
3128 | 30 | enum State { OffHook, OnHook }; | 32 | namespace media |
3129 | 31 | 33 | { | |
3130 | 32 | CallMonitor(); | 34 | namespace telephony |
3131 | 33 | ~CallMonitor(); | 35 | { |
3132 | 34 | 36 | // CallMonitor models the ability to observe and react | |
3133 | 35 | void on_change(const std::function<void(CallMonitor::State)>& func); | 37 | // to changes of the overall call state of the system. |
3134 | 36 | 38 | struct CallMonitor | |
3135 | 37 | private: | 39 | { |
3136 | 38 | CallMonitorPrivate *d; | 40 | // Save us some typing. |
3137 | 41 | typedef std::shared_ptr<CallMonitor> Ptr; | ||
3138 | 42 | |||
3139 | 43 | // All known call states | ||
3140 | 44 | enum class State | ||
3141 | 45 | { | ||
3142 | 46 | // No current call. | ||
3143 | 47 | OffHook, | ||
3144 | 48 | // Call in progress. | ||
3145 | 49 | OnHook | ||
3146 | 50 | }; | ||
3147 | 51 | |||
3148 | 52 | CallMonitor() = default; | ||
3149 | 53 | virtual ~CallMonitor() = default; | ||
3150 | 54 | |||
3151 | 55 | // Emitted whenever the current call state of the system changes. | ||
3152 | 56 | virtual const core::Signal<State>& on_call_state_changed() const = 0; | ||
3153 | 39 | }; | 57 | }; |
3154 | 40 | 58 | ||
3156 | 41 | #endif // CALLMONITOR_H | 59 | // Returns a platform default implementation of CallMonitor. |
3157 | 60 | CallMonitor::Ptr make_platform_default_call_monitor(); | ||
3158 | 61 | } | ||
3159 | 62 | } | ||
3160 | 63 | } | ||
3161 | 64 | } | ||
3162 | 65 | |||
3163 | 66 | #endif // CORE_UBUNTU_MEDIA_TELEPHONY_CALL_MONITOR_H_ |
FAILED: Continuous integration, rev:121 jenkins. qa.ubuntu. com/job/ media-hub- ci/304/ jenkins. qa.ubuntu. com/job/ media-hub- vivid-amd64- ci/144/ console jenkins. qa.ubuntu. com/job/ media-hub- vivid-armhf- ci/144 jenkins. qa.ubuntu. com/job/ media-hub- vivid-armhf- ci/144/ artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ media-hub- vivid-i386- ci/144
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/media- hub-ci/ 304/rebuild
http://