Merge lp:~phablet-team/media-hub/media-hub-condensed into lp:media-hub
- media-hub-condensed
- Merge into trunk
Status: | Merged | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Merged at revision: | 28 | ||||||||||||||||
Proposed branch: | lp:~phablet-team/media-hub/media-hub-condensed | ||||||||||||||||
Merge into: | lp:media-hub | ||||||||||||||||
Diff against target: |
2681 lines (+1434/-95) 39 files modified
CMakeLists.txt (+2/-0) debian/control (+3/-0) debian/media-hub.conf (+4/-1) debian/media-hub.install (+1/-0) debian/rules (+4/-0) debian/usr.bin.media-hub-server (+98/-0) include/core/media/player.h (+18/-3) include/core/media/service.h (+1/-0) src/core/media/CMakeLists.txt (+6/-2) src/core/media/apparmor.h (+51/-0) src/core/media/engine.h (+10/-0) src/core/media/gstreamer/engine.cpp (+105/-8) src/core/media/gstreamer/engine.h (+9/-0) src/core/media/gstreamer/playbin.h (+184/-20) src/core/media/mpris/player.h (+6/-0) src/core/media/mpris/service.h (+1/-0) src/core/media/player_implementation.cpp (+172/-17) src/core/media/player_implementation.h (+7/-1) src/core/media/player_skeleton.cpp (+221/-7) src/core/media/player_skeleton.h (+11/-0) src/core/media/player_stub.cpp (+197/-3) src/core/media/player_stub.h (+11/-0) src/core/media/powerd_service.h (+99/-0) src/core/media/server/server.cpp (+28/-0) src/core/media/service.cpp (+1/-1) src/core/media/service_implementation.cpp (+57/-10) src/core/media/service_implementation.h (+5/-0) src/core/media/service_skeleton.cpp (+17/-1) src/core/media/service_skeleton.h (+1/-1) src/core/media/service_stub.cpp (+13/-5) src/core/media/service_stub.h (+2/-1) src/core/media/track_list_implementation.cpp (+13/-0) src/core/media/track_list_implementation.h (+1/-0) src/core/media/track_list_skeleton.cpp (+15/-3) src/core/media/track_list_skeleton.h (+2/-1) tests/acceptance-tests/service.cpp (+1/-1) tests/unit-tests/CMakeLists.txt (+15/-1) tests/unit-tests/libmedia-mock.cpp (+26/-0) tests/unit-tests/test-gstreamer-engine.cpp (+16/-8) |
||||||||||||||||
To merge this branch: | bzr merge lp:~phablet-team/media-hub/media-hub-condensed | ||||||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Needs Fixing | |
Ubuntu Phablet Team | Pending | ||
Review via email: mp+217509@code.launchpad.net |
Commit message
* Merged with EOS branch from tvoss
* Added on_frame_available listener and callback
* Create a decoding session and pass it to the hybris layer
* Allow playback to work again after a client quits or dies
* Added two new properties to see if the opened media is video or audio
* Background playlist support
* Add powerd control interface
* One Engine instance per PlayerImplement
* Pause other playing sessions when starting playback of a new foreground player
* Emit a PlaybackStatusC
* Use GST_SEEK_
Description of the change
* Merged with EOS branch from tvoss
* Added on_frame_available listener and callback
* Create a decoding session and pass it to the hybris layer
* Allow playback to work again after a client quits or dies
* Added two new properties to see if the opened media is video or audio
* Background playlist support
* Add powerd control interface
* One Engine instance per PlayerImplement
* Pause other playing sessions when starting playback of a new foreground player
* Emit a PlaybackStatusC
* Use GST_SEEK_
PS Jenkins bot (ps-jenkins) wrote : | # |
- 31. By Jim Hodapp
-
Make sure media-hub respawns if it crashes
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:31
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2014-02-14 07:19:31 +0000 |
3 | +++ CMakeLists.txt 2014-04-30 01:13:03 +0000 |
4 | @@ -25,6 +25,8 @@ |
5 | pkg_check_modules(DBUS dbus-1 REQUIRED) |
6 | pkg_check_modules(DBUS_CPP dbus-cpp REQUIRED) |
7 | pkg_check_modules(PROPERTIES_CPP properties-cpp REQUIRED) |
8 | +pkg_check_modules(GIO gio-2.0 REQUIRED) |
9 | +pkg_check_modules(HYBRIS_MEDIA libmedia REQUIRED) |
10 | |
11 | ##################################################################### |
12 | # Enable code coverage calculation with gcov/gcovr/lcov |
13 | |
14 | === modified file 'debian/control' |
15 | --- debian/control 2014-03-26 20:18:20 +0000 |
16 | +++ debian/control 2014-04-30 01:13:03 +0000 |
17 | @@ -5,6 +5,7 @@ |
18 | Build-Depends: cmake, |
19 | dbus-test-runner, |
20 | debhelper (>= 9), |
21 | + dh-apparmor, |
22 | doxygen, |
23 | gcc-4.7, |
24 | g++-4.7, |
25 | @@ -39,6 +40,7 @@ |
26 | Depends: libmedia-hub-common0 (= ${binary:Version}), |
27 | libmedia-hub-client0 (= ${binary:Version}), |
28 | ${misc:Depends}, |
29 | + libproperties-cpp-dev, |
30 | Suggests: libmedia-hub-doc |
31 | Description: Simple and lightweight media playback service - development files |
32 | Media Hub is a simple and lightweight service for media playback using |
33 | @@ -51,6 +53,7 @@ |
34 | Pre-Depends: dpkg (>= 1.15.6~) |
35 | Depends: ${misc:Depends}, |
36 | ${shlibs:Depends}, |
37 | +Suggests: apparmor (>= 2.8.95~2430-0ubuntu4~) |
38 | Description: Simple and lightweight media playback service |
39 | Media Hub is a simple and lightweight service for media playback using |
40 | DBus. |
41 | |
42 | === modified file 'debian/media-hub.conf' |
43 | --- debian/media-hub.conf 2014-03-07 14:38:28 +0000 |
44 | +++ debian/media-hub.conf 2014-04-30 01:13:03 +0000 |
45 | @@ -1,6 +1,9 @@ |
46 | description "Starts the media-hub service" |
47 | |
48 | -start on dbus |
49 | +start on started dbus |
50 | stop on runlevel [06] |
51 | |
52 | +respawn |
53 | +respawn limit unlimited |
54 | + |
55 | exec media-hub-server |
56 | |
57 | === modified file 'debian/media-hub.install' |
58 | --- debian/media-hub.install 2014-03-06 22:51:51 +0000 |
59 | +++ debian/media-hub.install 2014-04-30 01:13:03 +0000 |
60 | @@ -1,2 +1,3 @@ |
61 | debian/media-hub.conf /usr/share/upstart/sessions/ |
62 | +debian/usr.bin.media-hub-server etc/apparmor.d |
63 | usr/bin |
64 | |
65 | === modified file 'debian/rules' |
66 | --- debian/rules 2014-03-07 22:49:23 +0000 |
67 | +++ debian/rules 2014-04-30 01:13:03 +0000 |
68 | @@ -14,3 +14,7 @@ |
69 | |
70 | override_dh_auto_test: |
71 | env -u LD_PRELOAD dh_auto_test |
72 | + |
73 | +override_dh_installdeb: |
74 | + dh_apparmor --profile-name=usr.bin.media-hub-server -pmedia-hub |
75 | + dh_installdeb |
76 | |
77 | === added file 'debian/usr.bin.media-hub-server' |
78 | --- debian/usr.bin.media-hub-server 1970-01-01 00:00:00 +0000 |
79 | +++ debian/usr.bin.media-hub-server 2014-04-30 01:13:03 +0000 |
80 | @@ -0,0 +1,98 @@ |
81 | +#include <tunables/global> |
82 | + |
83 | +/usr/bin/media-hub-server (attach_disconnected) { |
84 | + #include <abstractions/base> |
85 | + #include <abstractions/audio> |
86 | + #include <abstractions/nameservice> |
87 | + #include <abstractions/dbus-session> |
88 | + #include <abstractions/dbus-strict> |
89 | + #include <abstractions/user-tmp> |
90 | + #include "/usr/share/apparmor/hardware/audio.d" |
91 | + #include "/usr/share/apparmor/hardware/graphics.d" |
92 | + #include "/usr/share/apparmor/hardware/video.d" |
93 | + |
94 | + deny /dev/cpuctl/apps/tasks w, |
95 | + deny /dev/cpuctl/apps/bg_non_interactive/tasks w, |
96 | + |
97 | + @{PROC}/interrupts r, |
98 | + owner @{PROC}/cmdline r, |
99 | + owner @{PROC}/[0-9]*/auxv r, |
100 | + owner @{PROC}/[0-9]*/fd/ r, |
101 | + owner @{PROC}/[0-9]*/status r, |
102 | + owner @{PROC}/[0-9]*/task/ r, |
103 | + owner @{PROC}/[0-9]*/task/[0-9]*/ r, |
104 | + owner @{PROC}/[0-9]*/cmdline r, |
105 | + |
106 | + /sys/kernel/debug/tracing/trace_marker w, |
107 | + /dev/ashmem rw, |
108 | + |
109 | + # Explicitly deny this-- it is not needed |
110 | + /dev/fb0 rw, |
111 | + |
112 | + # libhybris |
113 | + /{,var/}run/shm/hybris_shm_data rw, |
114 | + /usr/lib/@{multiarch}/libhybris/*.so mr, |
115 | + /{,android/}system/build.prop r, |
116 | + # These libraries can be in any of: |
117 | + # /vendor/lib |
118 | + # /system/lib |
119 | + # /system/vendor/lib |
120 | + # /android/vendor/lib |
121 | + # /android/system/lib |
122 | + # /android/system/vendor/lib |
123 | + /{,android/}vendor/lib/** r, |
124 | + /{,android/}vendor/lib/**.so m, |
125 | + /{,android/}system/lib/** r, |
126 | + /{,android/}system/lib/**.so m, |
127 | + /{,android/}system/vendor/lib/** r, |
128 | + /{,android/}system/vendor/lib/**.so m, |
129 | + |
130 | + # attach_disconnected path |
131 | + /dev/socket/property_service rw, |
132 | + |
133 | + # Android logging triggered by platform. Can safely deny |
134 | + deny /dev/log_main w, |
135 | + deny /dev/log_radio w, |
136 | + deny /dev/log_events w, |
137 | + deny /dev/log_system w, |
138 | + |
139 | + # Allow all access to powerd for now, but we can fine-tune this if needed |
140 | + dbus (receive, send) |
141 | + bus=system |
142 | + path=/com/canonical/powerd |
143 | + interface=com.canonical.powerd, |
144 | + |
145 | + # GStreamer binary registry - hybris pulls this in for everything now, not |
146 | + # just audio |
147 | + owner @{HOME}/.gstreamer*/registry.*.bin* rw, |
148 | + owner @{HOME}/.gstreamer*/ rw, |
149 | + owner @{HOME}/.cache/gstreamer*/registry.*.bin* rw, |
150 | + |
151 | + /{,android/}system/etc/media_codecs.xml r, |
152 | + /etc/wildmidi/wildmidi.cfg r, |
153 | + |
154 | + audit deny owner /** m, |
155 | + |
156 | + # Allow read on all directories |
157 | + /**/ r, |
158 | + |
159 | + # Allow read on click install directories, removable media and files in |
160 | + # /usr/local/share. |
161 | + /usr/share/** r, |
162 | + /usr/local/share/** r, |
163 | + /{media,mnt,opt,srv}/** r, |
164 | + |
165 | + # Allow reading any files in non-hidden directories |
166 | + owner @{HOME}/[^.]* rk, |
167 | + owner @{HOME}/[^.]*/ rk, |
168 | + owner @{HOME}/[^.]*/** rk, |
169 | + |
170 | + # Allow reading files in XDG directories (ie, where apps are allowed to |
171 | + # write) |
172 | + owner @{HOME}/.cache/** rk, |
173 | + owner @{HOME}/.local/share/** rk, |
174 | + owner /{,var/}run/user/[0-9]*/** rk, |
175 | + |
176 | + # Site-specific additions and overrides. See local/README for details. |
177 | + #include <local/usr.bin.media-hub-server> |
178 | +} |
179 | |
180 | === modified file 'include/core/media/player.h' |
181 | --- include/core/media/player.h 2014-02-18 19:27:01 +0000 |
182 | +++ include/core/media/player.h 2014-04-30 01:13:03 +0000 |
183 | @@ -39,6 +39,13 @@ |
184 | public: |
185 | typedef double PlaybackRate; |
186 | typedef double Volume; |
187 | + typedef uint32_t PlayerKey; |
188 | + typedef void* GLConsumerWrapperHybris; |
189 | + |
190 | + /** Used to set a callback function to be called when a frame is ready to be rendered **/ |
191 | + typedef void (*FrameAvailableCbHybris)(GLConsumerWrapperHybris wrapper, void *context); |
192 | + typedef void (*FrameAvailableCb)(void *context); |
193 | + typedef void (*PlaybackCompleteCb)(void *context); |
194 | |
195 | struct Configuration; |
196 | |
197 | @@ -72,8 +79,11 @@ |
198 | bool operator==(const Player&) const = delete; |
199 | |
200 | virtual std::shared_ptr<TrackList> track_list() = 0; |
201 | + virtual PlayerKey key() const = 0; |
202 | |
203 | virtual bool open_uri(const Track::UriType& uri) = 0; |
204 | + virtual void create_video_sink(uint32_t texture_id) = 0; |
205 | + virtual GLConsumerWrapperHybris gl_consumer() const = 0; |
206 | virtual void next() = 0; |
207 | virtual void previous() = 0; |
208 | virtual void play() = 0; |
209 | @@ -81,11 +91,17 @@ |
210 | virtual void stop() = 0; |
211 | virtual void seek_to(const std::chrono::microseconds& offset) = 0; |
212 | |
213 | + // TODO: Convert this to be a signal |
214 | + virtual void set_frame_available_callback(FrameAvailableCb cb, void *context) = 0; |
215 | + virtual void set_playback_complete_callback(PlaybackCompleteCb cb, void *context) = 0; |
216 | + |
217 | virtual const core::Property<bool>& can_play() const = 0; |
218 | virtual const core::Property<bool>& can_pause() const = 0; |
219 | virtual const core::Property<bool>& can_seek() const = 0; |
220 | virtual const core::Property<bool>& can_go_previous() const = 0; |
221 | virtual const core::Property<bool>& can_go_next() const = 0; |
222 | + virtual const core::Property<bool>& is_video_source() const = 0; |
223 | + virtual const core::Property<bool>& is_audio_source() const = 0; |
224 | virtual const core::Property<PlaybackStatus>& playback_status() const = 0; |
225 | virtual const core::Property<LoopStatus>& loop_status() const = 0; |
226 | virtual const core::Property<PlaybackRate>& playback_rate() const = 0; |
227 | @@ -97,15 +113,14 @@ |
228 | virtual const core::Property<uint64_t>& position() const = 0; |
229 | virtual const core::Property<uint64_t>& duration() const = 0; |
230 | |
231 | - |
232 | virtual core::Property<LoopStatus>& loop_status() = 0; |
233 | virtual core::Property<PlaybackRate>& playback_rate() = 0; |
234 | virtual core::Property<bool>& is_shuffle() = 0; |
235 | virtual core::Property<Volume>& volume() = 0; |
236 | |
237 | - |
238 | virtual const core::Signal<uint64_t>& seeked_to() const = 0; |
239 | - |
240 | + virtual const core::Signal<void>& end_of_stream() const = 0; |
241 | + virtual core::Signal<PlaybackStatus>& playback_status_changed() = 0; |
242 | protected: |
243 | Player(); |
244 | |
245 | |
246 | === modified file 'include/core/media/service.h' |
247 | --- include/core/media/service.h 2014-01-13 21:51:14 +0000 |
248 | +++ include/core/media/service.h 2014-04-30 01:13:03 +0000 |
249 | @@ -43,6 +43,7 @@ |
250 | bool operator==(const Service&) const = delete; |
251 | |
252 | virtual std::shared_ptr<Player> create_session(const Player::Configuration&) = 0; |
253 | + virtual void pause_other_sessions(Player::PlayerKey) = 0; |
254 | |
255 | protected: |
256 | Service() = default; |
257 | |
258 | === modified file 'src/core/media/CMakeLists.txt' |
259 | --- src/core/media/CMakeLists.txt 2014-02-26 14:58:36 +0000 |
260 | +++ src/core/media/CMakeLists.txt 2014-04-30 01:13:03 +0000 |
261 | @@ -1,6 +1,6 @@ |
262 | pkg_check_modules(PC_GSTREAMER_1_0 REQUIRED gstreamer-1.0) |
263 | |
264 | -include_directories(${PC_GSTREAMER_1_0_INCLUDE_DIRS}) |
265 | +include_directories(${PC_GSTREAMER_1_0_INCLUDE_DIRS} ${HYBRIS_MEDIA_CFLAGS}) |
266 | |
267 | add_library( |
268 | media-hub-common SHARED |
269 | @@ -52,6 +52,7 @@ |
270 | ${DBUS_LIBRARIES} |
271 | ${DBUS_CPP_LDFLAGS} |
272 | ${GLog_LIBRARY} |
273 | + ${HYBRIS_MEDIA_LIBRARIES} |
274 | ) |
275 | |
276 | install( |
277 | @@ -82,9 +83,11 @@ |
278 | ${DBUS_CPP_LDFLAGS} |
279 | ${GLog_LIBRARY} |
280 | ${PC_GSTREAMER_1_0_LIBRARIES} |
281 | + ${GIO_LIBRARIES} |
282 | + ${HYBRIS_MEDIA_LIBRARIES} |
283 | ) |
284 | |
285 | -include_directories(${PROJECT_SOURCE_DIR}/src/) |
286 | +include_directories(${PROJECT_SOURCE_DIR}/src/ ${HYBRIS_MEDIA_CFLAGS}) |
287 | |
288 | add_executable( |
289 | media-hub-server |
290 | @@ -102,6 +105,7 @@ |
291 | ${DBUS_CPP_LDFLAGS} |
292 | ${GLog_LIBRARY} |
293 | ${PC_GSTREAMER_1_0_LIBRARIES} |
294 | + ${HYBRIS_MEDIA_LIBRARIES} |
295 | ) |
296 | |
297 | install( |
298 | |
299 | === added file 'src/core/media/apparmor.h' |
300 | --- src/core/media/apparmor.h 1970-01-01 00:00:00 +0000 |
301 | +++ src/core/media/apparmor.h 2014-04-30 01:13:03 +0000 |
302 | @@ -0,0 +1,51 @@ |
303 | +/* |
304 | + * Copyright (C) 2013-2014 Canonical Ltd |
305 | + * |
306 | + * This program is free software: you can redistribute it and/or modify |
307 | + * it under the terms of the GNU Lesser General Public License version 3 as |
308 | + * published by the Free Software Foundation. |
309 | + * |
310 | + * This program is distributed in the hope that it will be useful, |
311 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
312 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
313 | + * GNU Lesser General Public License for more details. |
314 | + * |
315 | + * You should have received a copy of the GNU Lesser General Public License |
316 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
317 | + * |
318 | + * Author: Jim Hodapp <jim.hodapp@canonical.com> |
319 | + */ |
320 | + |
321 | +#ifndef APPARMOR_H_DBUS_ |
322 | +#define APPARMOR_H_DBUS_ |
323 | + |
324 | +#include <string> |
325 | +#include <chrono> |
326 | + |
327 | +namespace core |
328 | +{ |
329 | + |
330 | +struct Apparmor |
331 | +{ |
332 | + static std::string& name() |
333 | + { |
334 | + static std::string s = "org.freedesktop.DBus"; |
335 | + return s; |
336 | + } |
337 | + |
338 | + struct getConnectionAppArmorSecurityContext |
339 | + { |
340 | + static std::string name() |
341 | + { |
342 | + static std::string s = "GetConnectionAppArmorSecurityContext"; |
343 | + return s; |
344 | + } |
345 | + |
346 | + static const std::chrono::milliseconds default_timeout() { return std::chrono::seconds{1}; } |
347 | + |
348 | + typedef Apparmor Interface; |
349 | + }; |
350 | +}; |
351 | +} |
352 | + |
353 | +#endif |
354 | |
355 | === modified file 'src/core/media/engine.h' |
356 | --- src/core/media/engine.h 2014-02-18 19:27:01 +0000 |
357 | +++ src/core/media/engine.h 2014-04-30 01:13:03 +0000 |
358 | @@ -18,6 +18,7 @@ |
359 | #ifndef CORE_UBUNTU_MEDIA_ENGINE_H_ |
360 | #define CORE_UBUNTU_MEDIA_ENGINE_H_ |
361 | |
362 | +#include <core/media/player.h> |
363 | #include <core/media/track.h> |
364 | |
365 | #include <core/property.h> |
366 | @@ -97,12 +98,16 @@ |
367 | virtual const core::Property<State>& state() const = 0; |
368 | |
369 | virtual bool open_resource_for_uri(const Track::UriType& uri) = 0; |
370 | + virtual void create_video_sink(uint32_t texture_id) = 0; |
371 | |
372 | virtual bool play() = 0; |
373 | virtual bool stop() = 0; |
374 | virtual bool pause() = 0; |
375 | virtual bool seek_to(const std::chrono::microseconds& ts) = 0; |
376 | |
377 | + virtual const core::Property<bool>& is_video_source() const = 0; |
378 | + virtual const core::Property<bool>& is_audio_source() const = 0; |
379 | + |
380 | virtual const core::Property<uint64_t>& position() const = 0; |
381 | virtual const core::Property<uint64_t>& duration() const = 0; |
382 | |
383 | @@ -110,6 +115,11 @@ |
384 | virtual core::Property<Volume>& volume() = 0; |
385 | |
386 | virtual const core::Property<std::tuple<Track::UriType, Track::MetaData>>& track_meta_data() const = 0; |
387 | + |
388 | + virtual const core::Signal<void>& about_to_finish_signal() const = 0; |
389 | + virtual const core::Signal<uint64_t>& seeked_to_signal() const = 0; |
390 | + virtual const core::Signal<void>& end_of_stream_signal() const = 0; |
391 | + virtual const core::Signal<core::ubuntu::media::Player::PlaybackStatus>& playback_status_changed_signal() const = 0; |
392 | }; |
393 | } |
394 | } |
395 | |
396 | === modified file 'src/core/media/gstreamer/engine.cpp' |
397 | --- src/core/media/gstreamer/engine.cpp 2014-02-20 19:05:17 +0000 |
398 | +++ src/core/media/gstreamer/engine.cpp 2014-04-30 01:13:03 +0000 |
399 | @@ -16,6 +16,9 @@ |
400 | * Authored by: Thomas Voß <thomas.voss@canonical.com> |
401 | */ |
402 | |
403 | +#include <stdio.h> |
404 | +#include <stdlib.h> |
405 | + |
406 | #include "bus.h" |
407 | #include "engine.h" |
408 | #include "meta_data_extractor.h" |
409 | @@ -25,6 +28,8 @@ |
410 | |
411 | namespace media = core::ubuntu::media; |
412 | |
413 | +using namespace std; |
414 | + |
415 | namespace gstreamer |
416 | { |
417 | struct Init |
418 | @@ -43,14 +48,10 @@ |
419 | |
420 | struct gstreamer::Engine::Private |
421 | { |
422 | - void about_to_finish() |
423 | - { |
424 | - state = Engine::State::ready; |
425 | - } |
426 | - |
427 | void on_playbin_state_changed( |
428 | - const gstreamer::Bus::Message::Detail::StateChanged&) |
429 | + const gstreamer::Bus::Message::Detail::StateChanged& state_change) |
430 | { |
431 | + (void) state_change; |
432 | } |
433 | |
434 | void on_tag_available(const gstreamer::Bus::Message::Detail::Tag& tag) |
435 | @@ -163,13 +164,31 @@ |
436 | playbin.set_volume(new_volume.value); |
437 | } |
438 | |
439 | + void on_about_to_finish() |
440 | + { |
441 | + state = Engine::State::ready; |
442 | + about_to_finish(); |
443 | + } |
444 | + |
445 | + void on_seeked_to(uint64_t value) |
446 | + { |
447 | + seeked_to(value); |
448 | + } |
449 | + |
450 | + void on_end_of_stream() |
451 | + { |
452 | + end_of_stream(); |
453 | + } |
454 | + |
455 | Private() |
456 | : meta_data_extractor(new gstreamer::MetaDataExtractor()), |
457 | volume(media::Engine::Volume(1.)), |
458 | + is_video_source(false), |
459 | + is_audio_source(false), |
460 | about_to_finish_connection( |
461 | playbin.signals.about_to_finish.connect( |
462 | std::bind( |
463 | - &Private::about_to_finish, |
464 | + &Private::on_about_to_finish, |
465 | this))), |
466 | on_state_changed_connection( |
467 | playbin.signals.on_state_changed.connect( |
468 | @@ -188,7 +207,18 @@ |
469 | std::bind( |
470 | &Private::on_volume_changed, |
471 | this, |
472 | - std::placeholders::_1))) |
473 | + std::placeholders::_1))), |
474 | + on_seeked_to_connection( |
475 | + playbin.signals.on_seeked_to.connect( |
476 | + std::bind( |
477 | + &Private::on_seeked_to, |
478 | + this, |
479 | + std::placeholders::_1))), |
480 | + on_end_of_stream_connection( |
481 | + playbin.signals.on_end_of_stream.connect( |
482 | + std::bind( |
483 | + &Private::on_end_of_stream, |
484 | + this))) |
485 | { |
486 | } |
487 | |
488 | @@ -198,15 +228,25 @@ |
489 | core::Property<uint64_t> position; |
490 | core::Property<uint64_t> duration; |
491 | core::Property<media::Engine::Volume> volume; |
492 | + core::Property<bool> is_video_source; |
493 | + core::Property<bool> is_audio_source; |
494 | gstreamer::Playbin playbin; |
495 | core::ScopedConnection about_to_finish_connection; |
496 | core::ScopedConnection on_state_changed_connection; |
497 | core::ScopedConnection on_tag_available_connection; |
498 | core::ScopedConnection on_volume_changed_connection; |
499 | + core::ScopedConnection on_seeked_to_connection; |
500 | + core::ScopedConnection on_end_of_stream_connection; |
501 | + |
502 | + core::Signal<void> about_to_finish; |
503 | + core::Signal<uint64_t> seeked_to; |
504 | + core::Signal<void> end_of_stream; |
505 | + core::Signal<media::Player::PlaybackStatus> playback_status_changed; |
506 | }; |
507 | |
508 | gstreamer::Engine::Engine() : d(new Private{}) |
509 | { |
510 | + cout << "Creating a new Engine instance in " << __PRETTY_FUNCTION__ << endl; |
511 | d->state = media::Engine::State::ready; |
512 | } |
513 | |
514 | @@ -231,6 +271,11 @@ |
515 | return true; |
516 | } |
517 | |
518 | +void gstreamer::Engine::create_video_sink(uint32_t texture_id) |
519 | +{ |
520 | + d->playbin.create_video_sink(texture_id); |
521 | +} |
522 | + |
523 | bool gstreamer::Engine::play() |
524 | { |
525 | auto result = d->playbin.set_state_and_wait(GST_STATE_PLAYING); |
526 | @@ -238,8 +283,11 @@ |
527 | if (result) |
528 | { |
529 | d->state = media::Engine::State::playing; |
530 | + d->playback_status_changed(media::Player::PlaybackStatus::playing); |
531 | } |
532 | |
533 | + cout << "Engine: " << this << endl; |
534 | + |
535 | return result; |
536 | } |
537 | |
538 | @@ -248,7 +296,10 @@ |
539 | auto result = d->playbin.set_state_and_wait(GST_STATE_NULL); |
540 | |
541 | if (result) |
542 | + { |
543 | d->state = media::Engine::State::stopped; |
544 | + d->playback_status_changed(media::Player::PlaybackStatus::stopped); |
545 | + } |
546 | |
547 | return result; |
548 | } |
549 | @@ -258,7 +309,11 @@ |
550 | auto result = d->playbin.set_state_and_wait(GST_STATE_PAUSED); |
551 | |
552 | if (result) |
553 | + { |
554 | d->state = media::Engine::State::paused; |
555 | + cout << "pause" << endl; |
556 | + d->playback_status_changed(media::Player::PlaybackStatus::paused); |
557 | + } |
558 | |
559 | return result; |
560 | } |
561 | @@ -268,6 +323,28 @@ |
562 | return d->playbin.seek(ts); |
563 | } |
564 | |
565 | +const core::Property<bool>& gstreamer::Engine::is_video_source() const |
566 | +{ |
567 | + gstreamer::Playbin::MediaFileType type = d->playbin.media_file_type(); |
568 | + if (type == gstreamer::Playbin::MediaFileType::MEDIA_FILE_TYPE_VIDEO) |
569 | + d->is_video_source.set(true); |
570 | + else |
571 | + d->is_video_source.set(false); |
572 | + |
573 | + return d->is_video_source; |
574 | +} |
575 | + |
576 | +const core::Property<bool>& gstreamer::Engine::is_audio_source() const |
577 | +{ |
578 | + gstreamer::Playbin::MediaFileType type = d->playbin.media_file_type(); |
579 | + if (type == gstreamer::Playbin::MediaFileType::MEDIA_FILE_TYPE_AUDIO) |
580 | + d->is_audio_source.set(true); |
581 | + else |
582 | + d->is_audio_source.set(false); |
583 | + |
584 | + return d->is_audio_source; |
585 | +} |
586 | + |
587 | const core::Property<uint64_t>& gstreamer::Engine::position() const |
588 | { |
589 | d->position.set(d->playbin.position()); |
590 | @@ -295,3 +372,23 @@ |
591 | { |
592 | return d->track_meta_data; |
593 | } |
594 | + |
595 | +const core::Signal<void>& gstreamer::Engine::about_to_finish_signal() const |
596 | +{ |
597 | + return d->about_to_finish; |
598 | +} |
599 | + |
600 | +const core::Signal<uint64_t>& gstreamer::Engine::seeked_to_signal() const |
601 | +{ |
602 | + return d->seeked_to; |
603 | +} |
604 | + |
605 | +const core::Signal<void>& gstreamer::Engine::end_of_stream_signal() const |
606 | +{ |
607 | + return d->end_of_stream; |
608 | +} |
609 | + |
610 | +const core::Signal<media::Player::PlaybackStatus>& gstreamer::Engine::playback_status_changed_signal() const |
611 | +{ |
612 | + return d->playback_status_changed; |
613 | +} |
614 | |
615 | === modified file 'src/core/media/gstreamer/engine.h' |
616 | --- src/core/media/gstreamer/engine.h 2014-02-18 19:27:01 +0000 |
617 | +++ src/core/media/gstreamer/engine.h 2014-04-30 01:13:03 +0000 |
618 | @@ -33,12 +33,16 @@ |
619 | const core::Property<State>& state() const; |
620 | |
621 | bool open_resource_for_uri(const core::ubuntu::media::Track::UriType& uri); |
622 | + void create_video_sink(uint32_t texture_id); |
623 | |
624 | bool play(); |
625 | bool stop(); |
626 | bool pause(); |
627 | bool seek_to(const std::chrono::microseconds& ts); |
628 | |
629 | + const core::Property<bool>& is_video_source() const; |
630 | + const core::Property<bool>& is_audio_source() const; |
631 | + |
632 | const core::Property<uint64_t>& position() const; |
633 | const core::Property<uint64_t>& duration() const; |
634 | |
635 | @@ -47,6 +51,11 @@ |
636 | |
637 | const core::Property<std::tuple<core::ubuntu::media::Track::UriType, core::ubuntu::media::Track::MetaData>>& track_meta_data() const; |
638 | |
639 | + const core::Signal<void>& about_to_finish_signal() const; |
640 | + const core::Signal<uint64_t>& seeked_to_signal() const; |
641 | + const core::Signal<void>& end_of_stream_signal() const; |
642 | + const core::Signal<core::ubuntu::media::Player::PlaybackStatus>& playback_status_changed_signal() const; |
643 | + |
644 | private: |
645 | struct Private; |
646 | std::unique_ptr<Private> d; |
647 | |
648 | === modified file 'src/core/media/gstreamer/playbin.h' |
649 | --- src/core/media/gstreamer/playbin.h 2014-02-20 19:05:17 +0000 |
650 | +++ src/core/media/gstreamer/playbin.h 2014-04-30 01:13:03 +0000 |
651 | @@ -20,12 +20,19 @@ |
652 | #define GSTREAMER_PLAYBIN_H_ |
653 | |
654 | #include "bus.h" |
655 | - |
656 | +#include "../mpris/player.h" |
657 | + |
658 | +#include <hybris/media/media_codec_layer.h> |
659 | +#include <hybris/media/surface_texture_client_hybris.h> |
660 | + |
661 | +#include <gio/gio.h> |
662 | #include <gst/gst.h> |
663 | |
664 | #include <chrono> |
665 | #include <string> |
666 | |
667 | +namespace media = core::ubuntu::media; |
668 | + |
669 | namespace gstreamer |
670 | { |
671 | struct Playbin |
672 | @@ -37,6 +44,13 @@ |
673 | GST_PLAY_FLAG_TEXT = (1 << 2) |
674 | }; |
675 | |
676 | + enum MediaFileType |
677 | + { |
678 | + MEDIA_FILE_TYPE_NONE, |
679 | + MEDIA_FILE_TYPE_AUDIO, |
680 | + MEDIA_FILE_TYPE_VIDEO |
681 | + }; |
682 | + |
683 | static const std::string& pipeline_name() |
684 | { |
685 | static const std::string s{"playbin"}; |
686 | @@ -45,20 +59,22 @@ |
687 | |
688 | static void about_to_finish(GstElement*, |
689 | gpointer user_data) |
690 | - { auto thiz = static_cast<Playbin*>(user_data); |
691 | - |
692 | + { |
693 | + auto thiz = static_cast<Playbin*>(user_data); |
694 | thiz->signals.about_to_finish(); |
695 | } |
696 | |
697 | Playbin() |
698 | : pipeline(gst_element_factory_make("playbin", pipeline_name().c_str())), |
699 | bus{gst_element_get_bus(pipeline)}, |
700 | + file_type(MEDIA_FILE_TYPE_NONE), |
701 | on_new_message_connection( |
702 | bus.on_new_message.connect( |
703 | std::bind( |
704 | &Playbin::on_new_message, |
705 | this, |
706 | - std::placeholders::_1))) |
707 | + std::placeholders::_1))), |
708 | + is_seeking(false) |
709 | { |
710 | if (!pipeline) |
711 | throw std::runtime_error("Could not create pipeline for playbin."); |
712 | @@ -74,6 +90,8 @@ |
713 | this |
714 | ); |
715 | |
716 | + // When a client of media-hub dies, call on_client_died |
717 | + decoding_service_set_client_death_cb(&Playbin::on_client_died_cb, static_cast<void*>(this)); |
718 | } |
719 | |
720 | ~Playbin() |
721 | @@ -82,6 +100,43 @@ |
722 | gst_object_unref(pipeline); |
723 | } |
724 | |
725 | + static void on_client_died_cb(void *context) |
726 | + { |
727 | + if (context) |
728 | + { |
729 | + Playbin *pb = static_cast<Playbin*>(context); |
730 | + pb->on_client_died(); |
731 | + } |
732 | + } |
733 | + |
734 | + void on_client_died() |
735 | + { |
736 | + std::cout << "Client died, resetting pipeline" << std::endl; |
737 | + // When the client dies, tear down the current pipeline and get it |
738 | + // in a state that is ready for the next client that connects to the |
739 | + // service |
740 | + reset_pipeline(); |
741 | + } |
742 | + |
743 | + void reset_pipeline() |
744 | + { |
745 | + std::cout << __PRETTY_FUNCTION__ << std::endl; |
746 | + auto ret = gst_element_set_state(pipeline, GST_STATE_NULL); |
747 | + switch(ret) |
748 | + { |
749 | + case GST_STATE_CHANGE_FAILURE: |
750 | + std::cout << "Failed to reset the pipeline state. Client reconnect may not function properly." << std::endl; |
751 | + break; |
752 | + case GST_STATE_CHANGE_NO_PREROLL: |
753 | + case GST_STATE_CHANGE_SUCCESS: |
754 | + case GST_STATE_CHANGE_ASYNC: |
755 | + break; |
756 | + default: |
757 | + std::cout << "Failed to reset the pipeline state. Client reconnect may not function properly." << std::endl; |
758 | + } |
759 | + file_type = MEDIA_FILE_TYPE_NONE; |
760 | + } |
761 | + |
762 | void on_new_message(const Bus::Message& message) |
763 | { |
764 | switch(message.type) |
765 | @@ -101,6 +156,16 @@ |
766 | case GST_MESSAGE_STATE_CHANGED: |
767 | signals.on_state_changed(message.detail.state_changed); |
768 | break; |
769 | + case GST_MESSAGE_ASYNC_DONE: |
770 | + if (is_seeking) |
771 | + { |
772 | + // FIXME: Pass the actual playback time position to the signal call |
773 | + signals.on_seeked_to(0); |
774 | + is_seeking = false; |
775 | + } |
776 | + break; |
777 | + case GST_MESSAGE_EOS: |
778 | + signals.on_end_of_stream(); |
779 | default: |
780 | break; |
781 | } |
782 | @@ -126,6 +191,8 @@ |
783 | ::getenv("CORE_UBUNTU_MEDIA_SERVICE_AUDIO_SINK_NAME"), |
784 | "audio-sink"); |
785 | |
786 | + std::cout << "audio_sink: " << ::getenv("CORE_UBUNTU_MEDIA_SERVICE_AUDIO_SINK_NAME") << std::endl; |
787 | + |
788 | g_object_set ( |
789 | pipeline, |
790 | "audio-sink", |
791 | @@ -136,26 +203,41 @@ |
792 | if (::getenv("CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME") != nullptr) |
793 | { |
794 | auto video_sink = gst_element_factory_make ( |
795 | - ::getenv("CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME"), |
796 | - "video-sink"); |
797 | + ::getenv("CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME"), |
798 | + "video-sink"); |
799 | |
800 | std::cout << "video_sink: " << ::getenv("CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME") << std::endl; |
801 | |
802 | g_object_set ( |
803 | - pipeline, |
804 | - "video-sink", |
805 | - video_sink, |
806 | - NULL); |
807 | + pipeline, |
808 | + "video-sink", |
809 | + video_sink, |
810 | + NULL); |
811 | + } |
812 | + } |
813 | + |
814 | + void create_video_sink(uint32_t texture_id) |
815 | + { |
816 | + std::cout << "Creating video sink for texture_id: " << texture_id << std::endl; |
817 | + |
818 | + if (::getenv("CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME") != nullptr) |
819 | + { |
820 | + GstElement *video_sink = NULL; |
821 | + g_object_get (pipeline, "video_sink", &video_sink, NULL); |
822 | + |
823 | + // Get the service-side BufferQueue (IGraphicBufferProducer) and associate it with |
824 | + // the SurfaceTextureClientHybris instance |
825 | + IGBPWrapperHybris igbp = decoding_service_get_igraphicbufferproducer(); |
826 | + SurfaceTextureClientHybris stc = surface_texture_client_create_by_igbp(igbp); |
827 | + // Because mirsink is being loaded, we are definitely doing * hardware rendering. |
828 | + surface_texture_client_set_hardware_rendering (stc, TRUE); |
829 | + g_object_set (G_OBJECT (video_sink), "surface", static_cast<gpointer>(stc), static_cast<char*>(NULL)); |
830 | } |
831 | } |
832 | |
833 | void set_volume(double new_volume) |
834 | { |
835 | - g_object_set( |
836 | - pipeline, |
837 | - "volume", |
838 | - new_volume, |
839 | - NULL); |
840 | + g_object_set(pipeline, "volume", new_volume, NULL); |
841 | } |
842 | |
843 | uint64_t position() const |
844 | @@ -178,11 +260,11 @@ |
845 | |
846 | void set_uri(const std::string& uri) |
847 | { |
848 | - g_object_set( |
849 | - pipeline, |
850 | - "uri", |
851 | - uri.c_str(), |
852 | - NULL); |
853 | + g_object_set(pipeline, "uri", uri.c_str(), NULL); |
854 | + if (is_video_file(uri)) |
855 | + file_type = MEDIA_FILE_TYPE_VIDEO; |
856 | + else if (is_audio_file(uri)) |
857 | + file_type = MEDIA_FILE_TYPE_AUDIO; |
858 | } |
859 | |
860 | std::string uri() const |
861 | @@ -229,6 +311,7 @@ |
862 | |
863 | bool seek(const std::chrono::microseconds& ms) |
864 | { |
865 | + is_seeking = true; |
866 | return gst_element_seek_simple( |
867 | pipeline, |
868 | GST_FORMAT_TIME, |
869 | @@ -236,9 +319,87 @@ |
870 | ms.count() * 1000); |
871 | } |
872 | |
873 | + std::string get_file_content_type(const std::string& uri) const |
874 | + { |
875 | + if (uri.empty()) |
876 | + return std::string(); |
877 | + |
878 | + std::string filename(uri); |
879 | + std::cout << "filename: " << filename << std::endl; |
880 | + size_t pos = uri.find("file://"); |
881 | + if (pos != std::string::npos) |
882 | + filename = uri.substr(pos + 7, std::string::npos); |
883 | + else |
884 | + // Anything other than a file, for now claim that the type |
885 | + // is both audio and video. |
886 | + // FIXME: implement true net stream sampling and get the type from GstCaps |
887 | + return std::string("audio/video/"); |
888 | + |
889 | + |
890 | + GError *error = nullptr; |
891 | + std::unique_ptr<GFile, void(*)(void *)> file( |
892 | + g_file_new_for_path(filename.c_str()), g_object_unref); |
893 | + std::unique_ptr<GFileInfo, void(*)(void *)> info( |
894 | + g_file_query_info( |
895 | + file.get(), G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE "," |
896 | + G_FILE_ATTRIBUTE_ETAG_VALUE, G_FILE_QUERY_INFO_NONE, |
897 | + /* cancellable */ NULL, &error), |
898 | + g_object_unref); |
899 | + if (!info) |
900 | + { |
901 | + std::string error_str(error->message); |
902 | + g_error_free(error); |
903 | + |
904 | + std::cout << "Failed to query the URI for the presence of video content: " |
905 | + << error_str << std::endl; |
906 | + return std::string(); |
907 | + } |
908 | + |
909 | + std::string content_type(g_file_info_get_attribute_string( |
910 | + info.get(), G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE)); |
911 | + |
912 | + return content_type; |
913 | + } |
914 | + |
915 | + bool is_audio_file(const std::string& uri) const |
916 | + { |
917 | + if (uri.empty()) |
918 | + return false; |
919 | + |
920 | + if (get_file_content_type(uri).find("audio/") == 0) |
921 | + { |
922 | + std::cout << "Found audio content" << std::endl; |
923 | + return true; |
924 | + } |
925 | + |
926 | + return false; |
927 | + } |
928 | + |
929 | + bool is_video_file(const std::string& uri) const |
930 | + { |
931 | + if (uri.empty()) |
932 | + return false; |
933 | + |
934 | + if (get_file_content_type(uri).find("video/") == 0) |
935 | + { |
936 | + std::cout << "Found video content" << std::endl; |
937 | + return true; |
938 | + } |
939 | + |
940 | + return false; |
941 | + } |
942 | + |
943 | + MediaFileType media_file_type() const |
944 | + { |
945 | + return file_type; |
946 | + } |
947 | + |
948 | GstElement* pipeline; |
949 | gstreamer::Bus bus; |
950 | + MediaFileType file_type; |
951 | + SurfaceTextureClientHybris stc_hybris; |
952 | core::Connection on_new_message_connection; |
953 | + bool is_seeking; |
954 | struct |
955 | { |
956 | core::Signal<void> about_to_finish; |
957 | @@ -247,6 +408,9 @@ |
958 | core::Signal<Bus::Message::Detail::ErrorWarningInfo> on_info; |
959 | core::Signal<Bus::Message::Detail::Tag> on_tag_available; |
960 | core::Signal<Bus::Message::Detail::StateChanged> on_state_changed; |
961 | + core::Signal<uint64_t> on_seeked_to; |
962 | + core::Signal<void> on_end_of_stream; |
963 | + core::Signal<media::Player::PlaybackStatus> on_playback_status_changed; |
964 | } signals; |
965 | }; |
966 | } |
967 | |
968 | === modified file 'src/core/media/mpris/player.h' |
969 | --- src/core/media/mpris/player.h 2014-02-18 19:27:01 +0000 |
970 | +++ src/core/media/mpris/player.h 2014-04-30 01:13:03 +0000 |
971 | @@ -54,11 +54,15 @@ |
972 | METHOD(Play, Player, std::chrono::seconds(1)) |
973 | METHOD(Seek, Player, std::chrono::seconds(1)) |
974 | METHOD(SetPosition, Player, std::chrono::seconds(1)) |
975 | + METHOD(CreateVideoSink, Player, std::chrono::seconds(1)) |
976 | + METHOD(Key, Player, std::chrono::seconds(1)) |
977 | METHOD(OpenUri, Player, std::chrono::seconds(1)) |
978 | |
979 | struct Signals |
980 | { |
981 | SIGNAL(Seeked, Player, uint64_t) |
982 | + SIGNAL(EndOfStream, Player, void) |
983 | + SIGNAL(PlaybackStatusChanged, Player, core::ubuntu::media::Player::PlaybackStatus) |
984 | }; |
985 | |
986 | struct Properties |
987 | @@ -74,6 +78,8 @@ |
988 | READABLE_PROPERTY(Duration, Player, uint64_t) |
989 | READABLE_PROPERTY(MinimumRate, Player, double) |
990 | READABLE_PROPERTY(MaximumRate, Player, double) |
991 | + READABLE_PROPERTY(IsVideoSource, Player, bool) |
992 | + READABLE_PROPERTY(IsAudioSource, Player, bool) |
993 | READABLE_PROPERTY(CanGoNext, Player, bool) |
994 | READABLE_PROPERTY(CanGoPrevious, Player, bool) |
995 | READABLE_PROPERTY(CanPlay, Player, bool) |
996 | |
997 | === modified file 'src/core/media/mpris/service.h' |
998 | --- src/core/media/mpris/service.h 2014-01-13 21:51:14 +0000 |
999 | +++ src/core/media/mpris/service.h 2014-04-30 01:13:03 +0000 |
1000 | @@ -50,6 +50,7 @@ |
1001 | }; |
1002 | |
1003 | METHOD(CreateSession, Service, std::chrono::seconds(1)) |
1004 | + METHOD(PauseOtherSessions, Service, std::chrono::seconds(1)) |
1005 | }; |
1006 | } |
1007 | |
1008 | |
1009 | === modified file 'src/core/media/player_implementation.cpp' |
1010 | --- src/core/media/player_implementation.cpp 2014-02-18 20:25:21 +0000 |
1011 | +++ src/core/media/player_implementation.cpp 2014-04-30 01:13:03 +0000 |
1012 | @@ -17,39 +17,125 @@ |
1013 | |
1014 | #include "player_implementation.h" |
1015 | |
1016 | +#include <unistd.h> |
1017 | + |
1018 | #include "engine.h" |
1019 | #include "track_list_implementation.h" |
1020 | |
1021 | +#include "powerd_service.h" |
1022 | +#include "gstreamer/engine.h" |
1023 | + |
1024 | +#define UNUSED __attribute__((unused)) |
1025 | + |
1026 | namespace media = core::ubuntu::media; |
1027 | +namespace dbus = core::dbus; |
1028 | + |
1029 | +using namespace std; |
1030 | |
1031 | struct media::PlayerImplementation::Private |
1032 | { |
1033 | Private(PlayerImplementation* parent, |
1034 | const dbus::types::ObjectPath& session_path, |
1035 | const std::shared_ptr<media::Service>& service, |
1036 | - const std::shared_ptr<media::Engine>& engine) |
1037 | + PlayerImplementation::PlayerKey key) |
1038 | : parent(parent), |
1039 | service(service), |
1040 | - engine(engine), |
1041 | + engine(std::make_shared<gstreamer::Engine>()), |
1042 | session_path(session_path), |
1043 | track_list( |
1044 | new media::TrackListImplementation( |
1045 | session_path.as_string() + "/TrackList", |
1046 | - engine->meta_data_extractor())) |
1047 | + engine->meta_data_extractor())), |
1048 | + disp_lock_name("media-hub-video-playback"), |
1049 | + sys_lock_name("media-hub-music-playback"), |
1050 | + key(key) |
1051 | { |
1052 | + auto bus = std::shared_ptr<dbus::Bus>(new dbus::Bus(core::dbus::WellKnownBus::system)); |
1053 | + bus->install_executor(dbus::asio::make_executor(bus)); |
1054 | + |
1055 | + auto stub_service = dbus::Service::use_service(bus, dbus::traits::Service<core::Powerd>::interface_name()); |
1056 | + powerd_session = stub_service->object_for_path(dbus::types::ObjectPath("/com/canonical/powerd")); |
1057 | + |
1058 | engine->state().changed().connect( |
1059 | - [parent](const Engine::State& state) |
1060 | - { |
1061 | + [parent, this](const Engine::State& state) |
1062 | + { |
1063 | switch(state) |
1064 | { |
1065 | - case Engine::State::ready: parent->playback_status().set(media::Player::ready); break; |
1066 | - case Engine::State::playing: parent->playback_status().set(media::Player::playing); break; |
1067 | - case Engine::State::stopped: parent->playback_status().set(media::Player::stopped); break; |
1068 | - case Engine::State::paused: parent->playback_status().set(media::Player::paused); break; |
1069 | + case Engine::State::ready: |
1070 | + { |
1071 | + parent->playback_status().set(media::Player::ready); |
1072 | + clear_power_state(); |
1073 | + break; |
1074 | + } |
1075 | + case Engine::State::playing: |
1076 | + { |
1077 | + parent->playback_status().set(media::Player::playing); |
1078 | + request_power_state(); |
1079 | + break; |
1080 | + } |
1081 | + case Engine::State::stopped: |
1082 | + { |
1083 | + parent->playback_status().set(media::Player::stopped); |
1084 | + clear_power_state(); |
1085 | + break; |
1086 | + } |
1087 | + case Engine::State::paused: |
1088 | + { |
1089 | + parent->playback_status().set(media::Player::paused); |
1090 | + clear_power_state(); |
1091 | + break; |
1092 | + } |
1093 | default: |
1094 | break; |
1095 | }; |
1096 | - }); |
1097 | + }); |
1098 | + |
1099 | + } |
1100 | + |
1101 | + void request_power_state() |
1102 | + { |
1103 | + if (parent->is_video_source()) |
1104 | + { |
1105 | + if (disp_cookie.empty()) |
1106 | + { |
1107 | + auto result = powerd_session->invoke_method_synchronously<core::Powerd::requestDisplayState, std::string>(disp_lock_name, static_cast<int>(1), static_cast<unsigned int>(4)); |
1108 | + if (result.is_error()) |
1109 | + throw std::runtime_error(result.error().print()); |
1110 | + |
1111 | + disp_cookie = result.value(); |
1112 | + } |
1113 | + } |
1114 | + else |
1115 | + { |
1116 | + if (sys_cookie.empty()) |
1117 | + { |
1118 | + auto result = powerd_session->invoke_method_synchronously<core::Powerd::requestSysState, std::string>(sys_lock_name, static_cast<int>(1)); |
1119 | + if (result.is_error()) |
1120 | + throw std::runtime_error(result.error().print()); |
1121 | + |
1122 | + sys_cookie = result.value(); |
1123 | + } |
1124 | + } |
1125 | + } |
1126 | + |
1127 | + void clear_power_state() |
1128 | + { |
1129 | + if (parent->is_video_source()) |
1130 | + { |
1131 | + if (!disp_cookie.empty()) |
1132 | + { |
1133 | + powerd_session->invoke_method_synchronously<core::Powerd::clearDisplayState, void>(disp_cookie); |
1134 | + disp_cookie.clear(); |
1135 | + } |
1136 | + } |
1137 | + else |
1138 | + { |
1139 | + if (!sys_cookie.empty()) |
1140 | + { |
1141 | + powerd_session->invoke_method_synchronously<core::Powerd::clearSysState, void>(sys_cookie); |
1142 | + sys_cookie.clear(); |
1143 | + } |
1144 | + } |
1145 | } |
1146 | |
1147 | PlayerImplementation* parent; |
1148 | @@ -57,18 +143,24 @@ |
1149 | std::shared_ptr<Engine> engine; |
1150 | dbus::types::ObjectPath session_path; |
1151 | std::shared_ptr<TrackListImplementation> track_list; |
1152 | + std::shared_ptr<dbus::Object> powerd_session; |
1153 | + std::string disp_lock_name; |
1154 | + std::string sys_lock_name; |
1155 | + std::string disp_cookie; |
1156 | + std::string sys_cookie; |
1157 | + PlayerImplementation::PlayerKey key; |
1158 | }; |
1159 | |
1160 | media::PlayerImplementation::PlayerImplementation( |
1161 | const dbus::types::ObjectPath& session_path, |
1162 | const std::shared_ptr<Service>& service, |
1163 | - const std::shared_ptr<Engine>& engine) |
1164 | + PlayerKey key) |
1165 | : media::PlayerSkeleton(session_path), |
1166 | d(new Private( |
1167 | this, |
1168 | session_path, |
1169 | service, |
1170 | - engine)) |
1171 | + key)) |
1172 | { |
1173 | // Initializing default values for properties |
1174 | can_play().set(true); |
1175 | @@ -76,6 +168,8 @@ |
1176 | can_seek().set(true); |
1177 | can_go_previous().set(true); |
1178 | can_go_next().set(true); |
1179 | + is_video_source().set(false); |
1180 | + is_audio_source().set(false); |
1181 | is_shuffle().set(true); |
1182 | playback_rate().set(1.f); |
1183 | playback_status().set(Player::PlaybackStatus::null); |
1184 | @@ -98,6 +192,43 @@ |
1185 | return d->engine->duration().get(); |
1186 | }; |
1187 | duration().install(duration_getter); |
1188 | + |
1189 | + std::function<bool()> video_type_getter = [this]() |
1190 | + { |
1191 | + return d->engine->is_video_source().get(); |
1192 | + }; |
1193 | + is_video_source().install(video_type_getter); |
1194 | + |
1195 | + std::function<bool()> audio_type_getter = [this]() |
1196 | + { |
1197 | + return d->engine->is_audio_source().get(); |
1198 | + }; |
1199 | + is_audio_source().install(audio_type_getter); |
1200 | + |
1201 | + d->engine->about_to_finish_signal().connect([this]() |
1202 | + { |
1203 | + if (d->track_list->has_next()) |
1204 | + { |
1205 | + Track::UriType uri = d->track_list->query_uri_for_track(d->track_list->next()); |
1206 | + if (!uri.empty()) |
1207 | + d->parent->open_uri(uri); |
1208 | + } |
1209 | + }); |
1210 | + |
1211 | + d->engine->seeked_to_signal().connect([this](uint64_t value) |
1212 | + { |
1213 | + seeked_to()(value); |
1214 | + }); |
1215 | + |
1216 | + d->engine->end_of_stream_signal().connect([this]() |
1217 | + { |
1218 | + end_of_stream()(); |
1219 | + }); |
1220 | + |
1221 | + d->engine->playback_status_changed_signal().connect([this](const Player::PlaybackStatus& status) |
1222 | + { |
1223 | + playback_status_changed()(status); |
1224 | + }); |
1225 | } |
1226 | |
1227 | media::PlayerImplementation::~PlayerImplementation() |
1228 | @@ -109,11 +240,28 @@ |
1229 | return d->track_list; |
1230 | } |
1231 | |
1232 | +// TODO: Convert this to be a property instead of sync call |
1233 | +media::Player::PlayerKey media::PlayerImplementation::key() const |
1234 | +{ |
1235 | + return d->key; |
1236 | +} |
1237 | + |
1238 | bool media::PlayerImplementation::open_uri(const Track::UriType& uri) |
1239 | { |
1240 | return d->engine->open_resource_for_uri(uri); |
1241 | } |
1242 | |
1243 | +void media::PlayerImplementation::create_video_sink(uint32_t texture_id) |
1244 | +{ |
1245 | + d->engine->create_video_sink(texture_id); |
1246 | +} |
1247 | + |
1248 | +media::Player::GLConsumerWrapperHybris media::PlayerImplementation::gl_consumer() const |
1249 | +{ |
1250 | + // This method is client-side only and is simply a no-op for the service side |
1251 | + return NULL; |
1252 | +} |
1253 | + |
1254 | void media::PlayerImplementation::next() |
1255 | { |
1256 | } |
1257 | @@ -124,11 +272,6 @@ |
1258 | |
1259 | void media::PlayerImplementation::play() |
1260 | { |
1261 | - /*if (playback_status() == media::Player::null) |
1262 | - { |
1263 | - if (d->track_list->has_next()) |
1264 | - if (open_uri(d->track_list->next()->)) |
1265 | - }*/ |
1266 | d->engine->play(); |
1267 | } |
1268 | |
1269 | @@ -142,6 +285,18 @@ |
1270 | d->engine->stop(); |
1271 | } |
1272 | |
1273 | +void media::PlayerImplementation::set_frame_available_callback( |
1274 | + UNUSED FrameAvailableCb cb, UNUSED void *context) |
1275 | +{ |
1276 | + // This method is client-side only and is simply a no-op for the service side |
1277 | +} |
1278 | + |
1279 | +void media::PlayerImplementation::set_playback_complete_callback( |
1280 | + UNUSED PlaybackCompleteCb cb, UNUSED void *context) |
1281 | +{ |
1282 | + // This method is client-side only and is simply a no-op for the service side |
1283 | +} |
1284 | + |
1285 | void media::PlayerImplementation::seek_to(const std::chrono::microseconds& ms) |
1286 | { |
1287 | d->engine->seek_to(ms); |
1288 | |
1289 | === modified file 'src/core/media/player_implementation.h' |
1290 | --- src/core/media/player_implementation.h 2014-02-18 20:25:21 +0000 |
1291 | +++ src/core/media/player_implementation.h 2014-04-30 01:13:03 +0000 |
1292 | @@ -1,4 +1,5 @@ |
1293 | /* |
1294 | + * Copyright © 2013-2014 Canonical Ltd. |
1295 | * |
1296 | * This program is free software: you can redistribute it and/or modify it |
1297 | * under the terms of the GNU Lesser General Public License version 3, |
1298 | @@ -37,17 +38,22 @@ |
1299 | PlayerImplementation( |
1300 | const core::dbus::types::ObjectPath& session_path, |
1301 | const std::shared_ptr<Service>& service, |
1302 | - const std::shared_ptr<Engine>& engine); |
1303 | + PlayerKey key); |
1304 | ~PlayerImplementation(); |
1305 | |
1306 | virtual std::shared_ptr<TrackList> track_list(); |
1307 | + virtual PlayerKey key() const; |
1308 | |
1309 | virtual bool open_uri(const Track::UriType& uri); |
1310 | + virtual void create_video_sink(uint32_t texture_id); |
1311 | + virtual GLConsumerWrapperHybris gl_consumer() const; |
1312 | virtual void next(); |
1313 | virtual void previous(); |
1314 | virtual void play(); |
1315 | virtual void pause(); |
1316 | virtual void stop(); |
1317 | + virtual void set_frame_available_callback(FrameAvailableCb cb, void *context); |
1318 | + virtual void set_playback_complete_callback(PlaybackCompleteCb cb, void *context); |
1319 | virtual void seek_to(const std::chrono::microseconds& offset); |
1320 | |
1321 | private: |
1322 | |
1323 | === modified file 'src/core/media/player_skeleton.cpp' |
1324 | --- src/core/media/player_skeleton.cpp 2014-02-20 19:05:17 +0000 |
1325 | +++ src/core/media/player_skeleton.cpp 2014-04-30 01:13:03 +0000 |
1326 | @@ -1,5 +1,5 @@ |
1327 | /* |
1328 | - * Copyright © 2013 Canonical Ltd. |
1329 | + * Copyright © 2013-2014 Canonical Ltd. |
1330 | * |
1331 | * This program is free software: you can redistribute it and/or modify it |
1332 | * under the terms of the GNU Lesser General Public License version 3, |
1333 | @@ -16,6 +16,7 @@ |
1334 | * Authored by: Thomas Voß <thomas.voss@canonical.com> |
1335 | */ |
1336 | |
1337 | +#include "apparmor.h" |
1338 | #include "codec.h" |
1339 | #include "player_skeleton.h" |
1340 | #include "player_traits.h" |
1341 | @@ -27,6 +28,7 @@ |
1342 | #include <core/dbus/object.h> |
1343 | #include <core/dbus/property.h> |
1344 | #include <core/dbus/stub.h> |
1345 | +#include <core/dbus/asio/executor.h> |
1346 | |
1347 | namespace dbus = core::dbus; |
1348 | namespace media = core::ubuntu::media; |
1349 | @@ -36,6 +38,7 @@ |
1350 | Private(media::PlayerSkeleton* player, const dbus::types::ObjectPath& session) |
1351 | : impl(player), |
1352 | object(impl->access_service()->add_object_for_path(session)), |
1353 | + apparmor_session(nullptr), |
1354 | properties |
1355 | { |
1356 | object->get_property<mpris::Player::Properties::CanPlay>(), |
1357 | @@ -44,6 +47,8 @@ |
1358 | object->get_property<mpris::Player::Properties::CanControl>(), |
1359 | object->get_property<mpris::Player::Properties::CanGoNext>(), |
1360 | object->get_property<mpris::Player::Properties::CanGoPrevious>(), |
1361 | + object->get_property<mpris::Player::Properties::IsVideoSource>(), |
1362 | + object->get_property<mpris::Player::Properties::IsAudioSource>(), |
1363 | object->get_property<mpris::Player::Properties::PlaybackStatus>(), |
1364 | object->get_property<mpris::Player::Properties::LoopStatus>(), |
1365 | object->get_property<mpris::Player::Properties::PlaybackRate>(), |
1366 | @@ -54,6 +59,12 @@ |
1367 | object->get_property<mpris::Player::Properties::Duration>(), |
1368 | object->get_property<mpris::Player::Properties::MinimumRate>(), |
1369 | object->get_property<mpris::Player::Properties::MaximumRate>() |
1370 | + }, |
1371 | + signals |
1372 | + { |
1373 | + object->get_signal<mpris::Player::Signals::Seeked>(), |
1374 | + object->get_signal<mpris::Player::Signals::EndOfStream>(), |
1375 | + object->get_signal<mpris::Player::Signals::PlaybackStatusChanged>() |
1376 | } |
1377 | { |
1378 | } |
1379 | @@ -111,18 +122,130 @@ |
1380 | { |
1381 | } |
1382 | |
1383 | + void handle_create_video_sink(const core::dbus::Message::Ptr& in) |
1384 | + { |
1385 | + uint32_t texture_id; |
1386 | + in->reader() >> texture_id; |
1387 | + impl->create_video_sink(texture_id); |
1388 | + |
1389 | + auto reply = dbus::Message::make_method_return(in); |
1390 | + impl->access_bus()->send(reply); |
1391 | + } |
1392 | + |
1393 | + std::string get_client_apparmor_context(const core::dbus::Message::Ptr& msg) |
1394 | + { |
1395 | + auto bus = std::shared_ptr<dbus::Bus>(new dbus::Bus(core::dbus::WellKnownBus::session)); |
1396 | + bus->install_executor(dbus::asio::make_executor(bus)); |
1397 | + |
1398 | + auto stub_service = dbus::Service::use_service(bus, dbus::traits::Service<core::Apparmor>::interface_name()); |
1399 | + apparmor_session = stub_service->object_for_path(dbus::types::ObjectPath("/org/freedesktop/DBus")); |
1400 | + // Get the AppArmor security context for the client |
1401 | + auto result = apparmor_session->invoke_method_synchronously<core::Apparmor::getConnectionAppArmorSecurityContext, std::string>(msg->sender()); |
1402 | + if (result.is_error()) |
1403 | + { |
1404 | + std::cout << "Error getting apparmor profile: " << result.error().print() << std::endl; |
1405 | + return std::string(); |
1406 | + } |
1407 | + |
1408 | + return result.value(); |
1409 | + } |
1410 | + |
1411 | + bool does_client_have_access(const std::string& context, const std::string& uri) |
1412 | + { |
1413 | + if (context.empty() || uri.empty()) |
1414 | + { |
1415 | + std::cout << "Client denied access since context or uri are empty" << std::endl; |
1416 | + return false; |
1417 | + } |
1418 | + |
1419 | + if (context == "unconfined") |
1420 | + { |
1421 | + std::cout << "Client allowed access since it's unconfined" << std::endl; |
1422 | + return true; |
1423 | + } |
1424 | + |
1425 | + size_t pos = context.find_first_of('_'); |
1426 | + if (pos == std::string::npos) |
1427 | + { |
1428 | + std::cout << "Client denied access since it's an invalid apparmor security context" << std::endl; |
1429 | + return false; |
1430 | + } |
1431 | + |
1432 | + const std::string pkgname = context.substr(0, pos); |
1433 | + std::cout << "client pkgname: " << pkgname << std::endl; |
1434 | + std::cout << "uri: " << uri << std::endl; |
1435 | + |
1436 | + // All confined apps can access their own files |
1437 | + if (uri.find(std::string(".local/share/" + pkgname + "/")) != std::string::npos |
1438 | + || uri.find(std::string(".cache/" + pkgname + "/")) != std::string::npos) |
1439 | + { |
1440 | + std::cout << "Client can access content in ~/.local/share/" << pkgname << " or ~/.cache/" << pkgname << std::endl; |
1441 | + return true; |
1442 | + } |
1443 | + else if (uri.find(std::string("opt/click.ubuntu.com/")) != std::string::npos |
1444 | + && uri.find(pkgname) != std::string::npos) |
1445 | + { |
1446 | + std::cout << "Client can access content in own opt directory" << std::endl; |
1447 | + return true; |
1448 | + } |
1449 | + else if ((uri.find(std::string("/system/media/audio/ui/")) != std::string::npos |
1450 | + || uri.find(std::string("/android/system/media/audio/ui/")) != std::string::npos) |
1451 | + && pkgname == "com.ubuntu.camera") |
1452 | + { |
1453 | + std::cout << "Camera app can access ui sounds" << std::endl; |
1454 | + return true; |
1455 | + } |
1456 | + // TODO: Check if the trust store previously allowed direct access to uri |
1457 | + |
1458 | + // Check in ~/Music and ~/Videos |
1459 | + // TODO: when the trust store lands, check it to see if this app can access the dirs and |
1460 | + // then remove the explicit whitelist of the music-app |
1461 | + else if (pkgname == "com.ubuntu.music" && |
1462 | + (uri.find(std::string("Music/")) != std::string::npos |
1463 | + || uri.find(std::string("Videos/")) != std::string::npos)) |
1464 | + { |
1465 | + std::cout << "Client can access content in ~/Music or ~/Videos" << std::endl; |
1466 | + return true; |
1467 | + } |
1468 | + else if (uri.find(std::string("http://")) != std::string::npos |
1469 | + || uri.find(std::string("rtsp://")) != std::string::npos) |
1470 | + { |
1471 | + std::cout << "Client can access streaming content" << std::endl; |
1472 | + return true; |
1473 | + } |
1474 | + else |
1475 | + { |
1476 | + std::cout << "Client denied access to open_uri()" << std::endl; |
1477 | + return false; |
1478 | + } |
1479 | + } |
1480 | + |
1481 | + void handle_key(const core::dbus::Message::Ptr& in) |
1482 | + { |
1483 | + auto reply = dbus::Message::make_method_return(in); |
1484 | + reply->writer() << impl->key(); |
1485 | + impl->access_bus()->send(reply); |
1486 | + } |
1487 | + |
1488 | void handle_open_uri(const core::dbus::Message::Ptr& in) |
1489 | { |
1490 | Track::UriType uri; |
1491 | in->reader() >> uri; |
1492 | |
1493 | + std::string context = get_client_apparmor_context(in); |
1494 | + bool have_access = does_client_have_access(context, uri); |
1495 | + |
1496 | auto reply = dbus::Message::make_method_return(in); |
1497 | - reply->writer() << impl->open_uri(uri); |
1498 | + if (have_access) |
1499 | + reply->writer() << impl->open_uri(uri); |
1500 | + else |
1501 | + reply->writer() << false; |
1502 | impl->access_bus()->send(reply); |
1503 | } |
1504 | |
1505 | media::PlayerSkeleton* impl; |
1506 | dbus::Object::Ptr object; |
1507 | + dbus::Object::Ptr apparmor_session; |
1508 | struct |
1509 | { |
1510 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanPlay>> can_play; |
1511 | @@ -131,6 +254,8 @@ |
1512 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanControl>> can_control; |
1513 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanGoNext>> can_go_next; |
1514 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanGoPrevious>> can_go_previous; |
1515 | + std::shared_ptr<core::dbus::Property<mpris::Player::Properties::IsVideoSource>> is_video_source; |
1516 | + std::shared_ptr<core::dbus::Property<mpris::Player::Properties::IsAudioSource>> is_audio_source; |
1517 | |
1518 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::PlaybackStatus>> playback_status; |
1519 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::LoopStatus>> loop_status; |
1520 | @@ -144,10 +269,51 @@ |
1521 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MaximumRate>> maximum_playback_rate; |
1522 | } properties; |
1523 | |
1524 | - /*struct |
1525 | + struct Signals |
1526 | { |
1527 | - std::shared_ptr<dbus::Signal<mpris::Player::Signals::Seeked, uint64_t>> seeked; |
1528 | - } signals;*/ |
1529 | + typedef core::dbus::Signal<mpris::Player::Signals::Seeked, mpris::Player::Signals::Seeked::ArgumentType> DBusSeekedToSignal; |
1530 | + typedef core::dbus::Signal<mpris::Player::Signals::EndOfStream, mpris::Player::Signals::EndOfStream::ArgumentType> DBusEndOfStreamSignal; |
1531 | + typedef core::dbus::Signal<mpris::Player::Signals::PlaybackStatusChanged, mpris::Player::Signals::PlaybackStatusChanged::ArgumentType> DBusPlaybackStatusChangedSignal; |
1532 | + |
1533 | + Signals(const std::shared_ptr<DBusSeekedToSignal>& seeked, |
1534 | + const std::shared_ptr<DBusEndOfStreamSignal>& eos, |
1535 | + const std::shared_ptr<DBusPlaybackStatusChangedSignal>& status) |
1536 | + : dbus |
1537 | + { |
1538 | + seeked, |
1539 | + eos, |
1540 | + status |
1541 | + }, |
1542 | + seeked_to(), |
1543 | + end_of_stream(), |
1544 | + playback_status_changed() |
1545 | + { |
1546 | + seeked_to.connect([this](std::uint64_t value) |
1547 | + { |
1548 | + dbus.seeked_to->emit(value); |
1549 | + }); |
1550 | + |
1551 | + end_of_stream.connect([this]() |
1552 | + { |
1553 | + dbus.end_of_stream->emit(); |
1554 | + }); |
1555 | + |
1556 | + playback_status_changed.connect([this](const media::Player::PlaybackStatus& status) |
1557 | + { |
1558 | + dbus.playback_status_changed->emit(status); |
1559 | + }); |
1560 | + } |
1561 | + |
1562 | + struct DBus |
1563 | + { |
1564 | + std::shared_ptr<DBusSeekedToSignal> seeked_to; |
1565 | + std::shared_ptr<DBusEndOfStreamSignal> end_of_stream; |
1566 | + std::shared_ptr<DBusPlaybackStatusChangedSignal> playback_status_changed; |
1567 | + } dbus; |
1568 | + core::Signal<uint64_t> seeked_to; |
1569 | + core::Signal<void> end_of_stream; |
1570 | + core::Signal<media::Player::PlaybackStatus> playback_status_changed; |
1571 | + } signals; |
1572 | |
1573 | }; |
1574 | |
1575 | @@ -184,6 +350,14 @@ |
1576 | std::bind(&Private::handle_set_position, |
1577 | std::ref(d), |
1578 | std::placeholders::_1)); |
1579 | + d->object->install_method_handler<mpris::Player::CreateVideoSink>( |
1580 | + std::bind(&Private::handle_create_video_sink, |
1581 | + std::ref(d), |
1582 | + std::placeholders::_1)); |
1583 | + d->object->install_method_handler<mpris::Player::Key>( |
1584 | + std::bind(&Private::handle_key, |
1585 | + std::ref(d), |
1586 | + std::placeholders::_1)); |
1587 | d->object->install_method_handler<mpris::Player::OpenUri>( |
1588 | std::bind(&Private::handle_open_uri, |
1589 | std::ref(d), |
1590 | @@ -219,6 +393,16 @@ |
1591 | return *d->properties.can_go_next; |
1592 | } |
1593 | |
1594 | +const core::Property<bool>& media::PlayerSkeleton::is_video_source() const |
1595 | +{ |
1596 | + return *d->properties.is_video_source; |
1597 | +} |
1598 | + |
1599 | +const core::Property<bool>& media::PlayerSkeleton::is_audio_source() const |
1600 | +{ |
1601 | + return *d->properties.is_audio_source; |
1602 | +} |
1603 | + |
1604 | const core::Property<media::Player::PlaybackStatus>& media::PlayerSkeleton::playback_status() const |
1605 | { |
1606 | return *d->properties.playback_status; |
1607 | @@ -329,6 +513,17 @@ |
1608 | return *d->properties.can_go_next; |
1609 | } |
1610 | |
1611 | +core::Property<bool>& media::PlayerSkeleton::is_video_source() |
1612 | +{ |
1613 | + return *d->properties.is_video_source; |
1614 | +} |
1615 | + |
1616 | +core::Property<bool>& media::PlayerSkeleton::is_audio_source() |
1617 | +{ |
1618 | + return *d->properties.is_audio_source; |
1619 | +} |
1620 | + |
1621 | + |
1622 | core::Property<media::Track::MetaData>& media::PlayerSkeleton::meta_data_for_current_track() |
1623 | { |
1624 | return *d->properties.meta_data_for_current_track; |
1625 | @@ -346,6 +541,25 @@ |
1626 | |
1627 | const core::Signal<uint64_t>& media::PlayerSkeleton::seeked_to() const |
1628 | { |
1629 | - static const core::Signal<uint64_t> signal; |
1630 | - return signal; |
1631 | + return d->signals.seeked_to; |
1632 | +} |
1633 | + |
1634 | +core::Signal<uint64_t>& media::PlayerSkeleton::seeked_to() |
1635 | +{ |
1636 | + return d->signals.seeked_to; |
1637 | +} |
1638 | + |
1639 | +const core::Signal<void>& media::PlayerSkeleton::end_of_stream() const |
1640 | +{ |
1641 | + return d->signals.end_of_stream; |
1642 | +} |
1643 | + |
1644 | +core::Signal<void>& media::PlayerSkeleton::end_of_stream() |
1645 | +{ |
1646 | + return d->signals.end_of_stream; |
1647 | +} |
1648 | + |
1649 | +core::Signal<media::Player::PlaybackStatus>& media::PlayerSkeleton::playback_status_changed() |
1650 | +{ |
1651 | + return d->signals.playback_status_changed; |
1652 | } |
1653 | |
1654 | === modified file 'src/core/media/player_skeleton.h' |
1655 | --- src/core/media/player_skeleton.h 2014-02-18 19:27:01 +0000 |
1656 | +++ src/core/media/player_skeleton.h 2014-04-30 01:13:03 +0000 |
1657 | @@ -1,4 +1,6 @@ |
1658 | /** |
1659 | + * Copyright (C) 2013-2014 Canonical Ltd |
1660 | + * |
1661 | * This program is free software: you can redistribute it and/or modify it |
1662 | * under the terms of the GNU Lesser General Public License version 3, |
1663 | * as published by the Free Software Foundation. |
1664 | @@ -46,6 +48,8 @@ |
1665 | virtual const core::Property<bool>& can_seek() const; |
1666 | virtual const core::Property<bool>& can_go_previous() const; |
1667 | virtual const core::Property<bool>& can_go_next() const; |
1668 | + virtual const core::Property<bool>& is_video_source() const; |
1669 | + virtual const core::Property<bool>& is_audio_source() const; |
1670 | virtual const core::Property<PlaybackStatus>& playback_status() const; |
1671 | virtual const core::Property<LoopStatus>& loop_status() const; |
1672 | virtual const core::Property<PlaybackRate>& playback_rate() const; |
1673 | @@ -63,6 +67,8 @@ |
1674 | virtual core::Property<Volume>& volume(); |
1675 | |
1676 | virtual const core::Signal<uint64_t>& seeked_to() const; |
1677 | + virtual const core::Signal<void>& end_of_stream() const; |
1678 | + virtual core::Signal<PlaybackStatus>& playback_status_changed(); |
1679 | |
1680 | protected: |
1681 | PlayerSkeleton(const core::dbus::types::ObjectPath& session_path); |
1682 | @@ -73,12 +79,17 @@ |
1683 | virtual core::Property<bool>& can_seek(); |
1684 | virtual core::Property<bool>& can_go_previous(); |
1685 | virtual core::Property<bool>& can_go_next(); |
1686 | + virtual core::Property<bool>& is_video_source(); |
1687 | + virtual core::Property<bool>& is_audio_source(); |
1688 | virtual core::Property<Track::MetaData>& meta_data_for_current_track(); |
1689 | virtual core::Property<PlaybackRate>& minimum_playback_rate(); |
1690 | virtual core::Property<PlaybackRate>& maximum_playback_rate(); |
1691 | virtual core::Property<uint64_t>& position(); |
1692 | virtual core::Property<uint64_t>& duration(); |
1693 | |
1694 | + virtual core::Signal<uint64_t>& seeked_to(); |
1695 | + virtual core::Signal<void>& end_of_stream(); |
1696 | + |
1697 | private: |
1698 | struct Private; |
1699 | std::unique_ptr<Private> d; |
1700 | |
1701 | === modified file 'src/core/media/player_stub.cpp' |
1702 | --- src/core/media/player_stub.cpp 2014-02-20 19:05:17 +0000 |
1703 | +++ src/core/media/player_stub.cpp 2014-04-30 01:13:03 +0000 |
1704 | @@ -1,5 +1,5 @@ |
1705 | /* |
1706 | - * Copyright © 2013 Canonical Ltd. |
1707 | + * Copyright © 2013-2014 Canonical Ltd. |
1708 | * |
1709 | * This program is free software: you can redistribute it and/or modify it |
1710 | * under the terms of the GNU Lesser General Public License version 3, |
1711 | @@ -31,8 +31,14 @@ |
1712 | #include <core/dbus/property.h> |
1713 | #include <core/dbus/types/object_path.h> |
1714 | |
1715 | +// Hybris |
1716 | +#include <hybris/media/media_codec_layer.h> |
1717 | +#include <hybris/media/surface_texture_client_hybris.h> |
1718 | + |
1719 | #include <limits> |
1720 | |
1721 | +#define UNUSED __attribute__((unused)) |
1722 | + |
1723 | namespace dbus = core::dbus; |
1724 | namespace media = core::ubuntu::media; |
1725 | |
1726 | @@ -42,6 +48,12 @@ |
1727 | const std::shared_ptr<dbus::Service>& remote, |
1728 | const dbus::types::ObjectPath& path |
1729 | ) : parent(parent), |
1730 | + texture_id(0), |
1731 | + igbc_wrapper(nullptr), |
1732 | + glc_wrapper(nullptr), |
1733 | + decoding_session(decoding_service_create_session()), |
1734 | + frame_available_cb(nullptr), |
1735 | + frame_available_context(nullptr), |
1736 | path(path), |
1737 | object(remote->object_for_path(path)), |
1738 | properties |
1739 | @@ -52,6 +64,8 @@ |
1740 | object->get_property<mpris::Player::Properties::CanControl>(), |
1741 | object->get_property<mpris::Player::Properties::CanGoNext>(), |
1742 | object->get_property<mpris::Player::Properties::CanGoPrevious>(), |
1743 | + object->get_property<mpris::Player::Properties::IsVideoSource>(), |
1744 | + object->get_property<mpris::Player::Properties::IsAudioSource>(), |
1745 | object->get_property<mpris::Player::Properties::PlaybackStatus>(), |
1746 | object->get_property<mpris::Player::Properties::LoopStatus>(), |
1747 | object->get_property<mpris::Player::Properties::PlaybackRate>(), |
1748 | @@ -62,13 +76,68 @@ |
1749 | object->get_property<mpris::Player::Properties::Duration>(), |
1750 | object->get_property<mpris::Player::Properties::MinimumRate>(), |
1751 | object->get_property<mpris::Player::Properties::MaximumRate>() |
1752 | + }, |
1753 | + signals |
1754 | + { |
1755 | + object->get_signal<mpris::Player::Signals::Seeked>(), |
1756 | + object->get_signal<mpris::Player::Signals::EndOfStream>(), |
1757 | + object->get_signal<mpris::Player::Signals::PlaybackStatusChanged>() |
1758 | } |
1759 | { |
1760 | } |
1761 | |
1762 | + ~Private() |
1763 | + { |
1764 | + } |
1765 | + |
1766 | + static void on_frame_available_cb(UNUSED GLConsumerWrapperHybris wrapper, void *context) |
1767 | + { |
1768 | + if (context != nullptr) { |
1769 | + Private *p = static_cast<Private*>(context); |
1770 | + p->on_frame_available(); |
1771 | + } |
1772 | + else |
1773 | + std::cout << "context is nullptr, can't call on_frame_available()" << std::endl; |
1774 | + } |
1775 | + |
1776 | + void on_frame_available() |
1777 | + { |
1778 | + if (frame_available_cb != nullptr) { |
1779 | + frame_available_cb(frame_available_context); |
1780 | + } |
1781 | + else |
1782 | + std::cout << "frame_available_cb is nullptr, can't call frame_available_cb()" << std::endl; |
1783 | + } |
1784 | + |
1785 | + void set_frame_available_cb(FrameAvailableCb cb, void *context) |
1786 | + { |
1787 | + frame_available_cb = cb; |
1788 | + frame_available_context = context; |
1789 | + |
1790 | + gl_consumer_set_frame_available_cb(glc_wrapper, &Private::on_frame_available_cb, static_cast<void*>(this)); |
1791 | + } |
1792 | + |
1793 | + /** We need a GLConsumerHybris instance for doing texture streaming over the |
1794 | + * process boundary **/ |
1795 | + void get_gl_consumer() |
1796 | + { |
1797 | + igbc_wrapper = decoding_service_get_igraphicbufferconsumer(); |
1798 | + glc_wrapper = gl_consumer_create_by_id_with_igbc(texture_id, igbc_wrapper); |
1799 | + |
1800 | + } |
1801 | + |
1802 | std::shared_ptr<Service> parent; |
1803 | std::shared_ptr<TrackList> track_list; |
1804 | |
1805 | + uint32_t texture_id; |
1806 | + IGBCWrapperHybris igbc_wrapper; |
1807 | + GLConsumerWrapperHybris glc_wrapper; |
1808 | + |
1809 | + DSSessionWrapperHybris decoding_session; |
1810 | + |
1811 | + FrameAvailableCb frame_available_cb; |
1812 | + void *frame_available_context; |
1813 | + |
1814 | dbus::Bus::Ptr bus; |
1815 | dbus::types::ObjectPath path; |
1816 | dbus::Object::Ptr object; |
1817 | @@ -81,6 +150,8 @@ |
1818 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanControl>> can_control; |
1819 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanGoNext>> can_go_next; |
1820 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanGoPrevious>> can_go_previous; |
1821 | + std::shared_ptr<core::dbus::Property<mpris::Player::Properties::IsVideoSource>> is_video_source; |
1822 | + std::shared_ptr<core::dbus::Property<mpris::Player::Properties::IsAudioSource>> is_audio_source; |
1823 | |
1824 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::PlaybackStatus>> playback_status; |
1825 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::LoopStatus>> loop_status; |
1826 | @@ -93,6 +164,68 @@ |
1827 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MinimumRate>> minimum_playback_rate; |
1828 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MaximumRate>> maximum_playback_rate; |
1829 | } properties; |
1830 | + |
1831 | + struct Signals |
1832 | + { |
1833 | + typedef core::dbus::Signal<mpris::Player::Signals::Seeked, mpris::Player::Signals::Seeked::ArgumentType> DBusSeekedToSignal; |
1834 | + typedef core::dbus::Signal<mpris::Player::Signals::EndOfStream, mpris::Player::Signals::EndOfStream::ArgumentType> DBusEndOfStreamSignal; |
1835 | + typedef core::dbus::Signal<mpris::Player::Signals::PlaybackStatusChanged, mpris::Player::Signals::PlaybackStatusChanged::ArgumentType> DBusPlaybackStatusChangedSignal; |
1836 | + |
1837 | + Signals(const std::shared_ptr<DBusSeekedToSignal>& seeked, |
1838 | + const std::shared_ptr<DBusEndOfStreamSignal>& eos, |
1839 | + const std::shared_ptr<DBusPlaybackStatusChangedSignal>& status) |
1840 | + : dbus |
1841 | + { |
1842 | + seeked, |
1843 | + eos, |
1844 | + status |
1845 | + }, |
1846 | + playback_complete_cb(nullptr), |
1847 | + playback_complete_context(nullptr), |
1848 | + seeked_to(), |
1849 | + end_of_stream(), |
1850 | + playback_status_changed() |
1851 | + { |
1852 | + dbus.seeked_to->connect([this](std::uint64_t value) |
1853 | + { |
1854 | + std::cout << "seeked_to signal arrived via the bus." << std::endl; |
1855 | + seeked_to(value); |
1856 | + }); |
1857 | + |
1858 | + dbus.end_of_stream->connect([this]() |
1859 | + { |
1860 | + std::cout << "EndOfStream signal arrived via the bus." << std::endl; |
1861 | + if (playback_complete_cb) |
1862 | + playback_complete_cb(playback_complete_context); |
1863 | + end_of_stream(); |
1864 | + }); |
1865 | + |
1866 | + dbus.playback_status_changed->connect([this](const media::Player::PlaybackStatus& status) |
1867 | + { |
1868 | + std::cout << "PlaybackStatusChanged signal arrived via the bus." << std::endl; |
1869 | + playback_status_changed(status); |
1870 | + }); |
1871 | + } |
1872 | + |
1873 | + struct DBus |
1874 | + { |
1875 | + std::shared_ptr<DBusSeekedToSignal> seeked_to; |
1876 | + std::shared_ptr<DBusEndOfStreamSignal> end_of_stream; |
1877 | + std::shared_ptr<DBusPlaybackStatusChangedSignal> playback_status_changed; |
1878 | + } dbus; |
1879 | + |
1880 | + void set_playback_complete_cb(PlaybackCompleteCb cb, void *context) |
1881 | + { |
1882 | + playback_complete_cb = cb; |
1883 | + playback_complete_context = context; |
1884 | + } |
1885 | + |
1886 | + PlaybackCompleteCb playback_complete_cb; |
1887 | + void *playback_complete_context; |
1888 | + core::Signal<uint64_t> seeked_to; |
1889 | + core::Signal<void> end_of_stream; |
1890 | + core::Signal<media::Player::PlaybackStatus> playback_status_changed; |
1891 | + } signals; |
1892 | }; |
1893 | |
1894 | media::PlayerStub::PlayerStub( |
1895 | @@ -101,10 +234,20 @@ |
1896 | : dbus::Stub<Player>(the_session_bus()), |
1897 | d(new Private{parent, access_service(), object_path}) |
1898 | { |
1899 | + auto bus = the_session_bus(); |
1900 | + worker = std::move(std::thread([bus]() |
1901 | + { |
1902 | + bus->run(); |
1903 | + })); |
1904 | } |
1905 | |
1906 | media::PlayerStub::~PlayerStub() |
1907 | { |
1908 | + auto bus = the_session_bus(); |
1909 | + bus->stop(); |
1910 | + |
1911 | + if (worker.joinable()) |
1912 | + worker.join(); |
1913 | } |
1914 | |
1915 | std::shared_ptr<media::TrackList> media::PlayerStub::track_list() |
1916 | @@ -118,6 +261,13 @@ |
1917 | return d->track_list; |
1918 | } |
1919 | |
1920 | +media::Player::PlayerKey media::PlayerStub::key() const |
1921 | +{ |
1922 | + auto op = d->object->invoke_method_synchronously<mpris::Player::Key, media::Player::PlayerKey>(); |
1923 | + |
1924 | + return op.value(); |
1925 | +} |
1926 | + |
1927 | bool media::PlayerStub::open_uri(const media::Track::UriType& uri) |
1928 | { |
1929 | auto op = d->object->invoke_method_synchronously<mpris::Player::OpenUri, bool>(uri); |
1930 | @@ -125,6 +275,21 @@ |
1931 | return op.value(); |
1932 | } |
1933 | |
1934 | +void media::PlayerStub::create_video_sink(uint32_t texture_id) |
1935 | +{ |
1936 | + auto op = d->object->invoke_method_synchronously<mpris::Player::CreateVideoSink, void>(texture_id); |
1937 | + d->texture_id = texture_id; |
1938 | + d->get_gl_consumer(); |
1939 | + |
1940 | + if (op.is_error()) |
1941 | + throw std::runtime_error("Problem creating new video sink instance on remote object"); |
1942 | +} |
1943 | + |
1944 | +GLConsumerWrapperHybris media::PlayerStub::gl_consumer() const |
1945 | +{ |
1946 | + return d->glc_wrapper; |
1947 | +} |
1948 | + |
1949 | void media::PlayerStub::next() |
1950 | { |
1951 | auto op = d->object->invoke_method_synchronously<mpris::Player::Next, void>(); |
1952 | @@ -173,6 +338,16 @@ |
1953 | throw std::runtime_error("Problem stopping playback on remote object"); |
1954 | } |
1955 | |
1956 | +void media::PlayerStub::set_frame_available_callback(FrameAvailableCb cb, void *context) |
1957 | +{ |
1958 | + d->set_frame_available_cb(cb, context); |
1959 | +} |
1960 | + |
1961 | +void media::PlayerStub::set_playback_complete_callback(PlaybackCompleteCb cb, void *context) |
1962 | +{ |
1963 | + d->signals.set_playback_complete_cb(cb, context); |
1964 | +} |
1965 | + |
1966 | const core::Property<bool>& media::PlayerStub::can_play() const |
1967 | { |
1968 | return *d->properties.can_play; |
1969 | @@ -198,6 +373,16 @@ |
1970 | return *d->properties.can_go_next; |
1971 | } |
1972 | |
1973 | +const core::Property<bool>& media::PlayerStub::is_video_source() const |
1974 | +{ |
1975 | + return *d->properties.is_video_source; |
1976 | +} |
1977 | + |
1978 | +const core::Property<bool>& media::PlayerStub::is_audio_source() const |
1979 | +{ |
1980 | + return *d->properties.is_audio_source; |
1981 | +} |
1982 | + |
1983 | const core::Property<media::Player::PlaybackStatus>& media::PlayerStub::playback_status() const |
1984 | { |
1985 | return *d->properties.playback_status; |
1986 | @@ -270,6 +455,15 @@ |
1987 | |
1988 | const core::Signal<uint64_t>& media::PlayerStub::seeked_to() const |
1989 | { |
1990 | - static core::Signal<uint64_t> signal; |
1991 | - return signal; |
1992 | + return d->signals.seeked_to; |
1993 | +} |
1994 | + |
1995 | +const core::Signal<void>& media::PlayerStub::end_of_stream() const |
1996 | +{ |
1997 | + return d->signals.end_of_stream; |
1998 | +} |
1999 | + |
2000 | +core::Signal<media::Player::PlaybackStatus>& media::PlayerStub::playback_status_changed() |
2001 | +{ |
2002 | + return d->signals.playback_status_changed; |
2003 | } |
2004 | |
2005 | === modified file 'src/core/media/player_stub.h' |
2006 | --- src/core/media/player_stub.h 2014-02-18 19:27:01 +0000 |
2007 | +++ src/core/media/player_stub.h 2014-04-30 01:13:03 +0000 |
2008 | @@ -43,8 +43,11 @@ |
2009 | ~PlayerStub(); |
2010 | |
2011 | virtual std::shared_ptr<TrackList> track_list(); |
2012 | + virtual PlayerKey key() const; |
2013 | |
2014 | virtual bool open_uri(const Track::UriType& uri); |
2015 | + virtual void create_video_sink(uint32_t texture_id); |
2016 | + virtual GLConsumerWrapperHybris gl_consumer() const; |
2017 | virtual void next(); |
2018 | virtual void previous(); |
2019 | virtual void play(); |
2020 | @@ -52,11 +55,16 @@ |
2021 | virtual void seek_to(const std::chrono::microseconds& offset); |
2022 | virtual void stop(); |
2023 | |
2024 | + virtual void set_frame_available_callback(FrameAvailableCb cb, void *context); |
2025 | + virtual void set_playback_complete_callback(PlaybackCompleteCb cb, void *context); |
2026 | + |
2027 | virtual const core::Property<bool>& can_play() const; |
2028 | virtual const core::Property<bool>& can_pause() const; |
2029 | virtual const core::Property<bool>& can_seek() const; |
2030 | virtual const core::Property<bool>& can_go_previous() const; |
2031 | virtual const core::Property<bool>& can_go_next() const; |
2032 | + virtual const core::Property<bool>& is_video_source() const; |
2033 | + virtual const core::Property<bool>& is_audio_source() const; |
2034 | virtual const core::Property<PlaybackStatus>& playback_status() const; |
2035 | virtual const core::Property<LoopStatus>& loop_status() const; |
2036 | virtual const core::Property<PlaybackRate>& playback_rate() const; |
2037 | @@ -74,10 +82,13 @@ |
2038 | virtual core::Property<Volume>& volume(); |
2039 | |
2040 | virtual const core::Signal<uint64_t>& seeked_to() const; |
2041 | + virtual const core::Signal<void>& end_of_stream() const; |
2042 | + virtual core::Signal<PlaybackStatus>& playback_status_changed(); |
2043 | |
2044 | private: |
2045 | struct Private; |
2046 | std::unique_ptr<Private> d; |
2047 | + std::thread worker; |
2048 | }; |
2049 | } |
2050 | } |
2051 | |
2052 | === added file 'src/core/media/powerd_service.h' |
2053 | --- src/core/media/powerd_service.h 1970-01-01 00:00:00 +0000 |
2054 | +++ src/core/media/powerd_service.h 2014-04-30 01:13:03 +0000 |
2055 | @@ -0,0 +1,99 @@ |
2056 | +/* |
2057 | + * Copyright (C) 2014 Canonical Ltd |
2058 | + * |
2059 | + * This program is free software: you can redistribute it and/or modify |
2060 | + * it under the terms of the GNU Lesser General Public License version 3 as |
2061 | + * published by the Free Software Foundation. |
2062 | + * |
2063 | + * This program is distributed in the hope that it will be useful, |
2064 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2065 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2066 | + * GNU Lesser General Public License for more details. |
2067 | + * |
2068 | + * You should have received a copy of the GNU Lesser General Public License |
2069 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2070 | + * |
2071 | + * Author: Ricardo Mendoza <ricardo.mendoza@canonical.com> |
2072 | + */ |
2073 | + |
2074 | +#include <core/dbus/dbus.h> |
2075 | +#include <core/dbus/fixture.h> |
2076 | +#include <core/dbus/object.h> |
2077 | +#include <core/dbus/property.h> |
2078 | +#include <core/dbus/service.h> |
2079 | +#include <core/dbus/interfaces/properties.h> |
2080 | +#include <core/dbus/types/stl/tuple.h> |
2081 | +#include <core/dbus/types/stl/vector.h> |
2082 | + |
2083 | +#include <core/dbus/asio/executor.h> |
2084 | + |
2085 | +#include <string> |
2086 | +#include <vector> |
2087 | +#include <chrono> |
2088 | + |
2089 | +namespace core |
2090 | +{ |
2091 | + |
2092 | +struct Powerd |
2093 | +{ |
2094 | + static std::string& name() |
2095 | + { |
2096 | + static std::string s = "com.canonical.powerd"; |
2097 | + return s; |
2098 | + } |
2099 | + |
2100 | + struct requestDisplayState |
2101 | + { |
2102 | + static std::string name() |
2103 | + { |
2104 | + static std::string s = "requestDisplayState"; |
2105 | + return s; |
2106 | + } |
2107 | + |
2108 | + static const std::chrono::milliseconds default_timeout() { return std::chrono::seconds{1}; } |
2109 | + |
2110 | + typedef Powerd Interface; |
2111 | + }; |
2112 | + |
2113 | + struct clearDisplayState |
2114 | + { |
2115 | + static std::string name() |
2116 | + { |
2117 | + static std::string s = "clearDisplayState"; |
2118 | + return s; |
2119 | + } |
2120 | + |
2121 | + static const std::chrono::milliseconds default_timeout() { return std::chrono::seconds{1}; } |
2122 | + |
2123 | + typedef Powerd Interface; |
2124 | + }; |
2125 | + |
2126 | + struct requestSysState |
2127 | + { |
2128 | + static std::string name() |
2129 | + { |
2130 | + static std::string s = "requestSysState"; |
2131 | + return s; |
2132 | + } |
2133 | + |
2134 | + static const std::chrono::milliseconds default_timeout() { return std::chrono::seconds{1}; } |
2135 | + |
2136 | + typedef Powerd Interface; |
2137 | + }; |
2138 | + |
2139 | + struct clearSysState |
2140 | + { |
2141 | + static std::string name() |
2142 | + { |
2143 | + static std::string s = "clearSysState"; |
2144 | + return s; |
2145 | + } |
2146 | + |
2147 | + static const std::chrono::milliseconds default_timeout() { return std::chrono::seconds{1}; } |
2148 | + |
2149 | + typedef Powerd Interface; |
2150 | + }; |
2151 | + |
2152 | +}; |
2153 | + |
2154 | +} |
2155 | |
2156 | === modified file 'src/core/media/server/server.cpp' |
2157 | --- src/core/media/server/server.cpp 2014-02-12 15:53:57 +0000 |
2158 | +++ src/core/media/server/server.cpp 2014-04-30 01:13:03 +0000 |
2159 | @@ -1,13 +1,41 @@ |
2160 | +/* |
2161 | + * Copyright (C) 2014 Canonical Ltd |
2162 | + * |
2163 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
2164 | + * you may not use this file except in compliance with the License. |
2165 | + * You may obtain a copy of the License at |
2166 | + * |
2167 | + * http://www.apache.org/licenses/LICENSE-2.0 |
2168 | + * |
2169 | + * Unless required by applicable law or agreed to in writing, software |
2170 | + * distributed under the License is distributed on an "AS IS" BASIS, |
2171 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
2172 | + * See the License for the specific language governing permissions and |
2173 | + * limitations under the License. |
2174 | + * |
2175 | + * Authored by: Jim Hodapp <jim.hodapp@canonical.com> |
2176 | + */ |
2177 | + |
2178 | #include <core/media/service.h> |
2179 | #include <core/media/player.h> |
2180 | #include <core/media/track_list.h> |
2181 | |
2182 | +#include <hybris/media/media_codec_layer.h> |
2183 | + |
2184 | #include "core/media/service_implementation.h" |
2185 | |
2186 | +#include <iostream> |
2187 | + |
2188 | namespace media = core::ubuntu::media; |
2189 | |
2190 | +using namespace std; |
2191 | + |
2192 | int main() |
2193 | { |
2194 | + // Init hybris-level DecodingService |
2195 | + decoding_service_init(); |
2196 | + cout << "Starting DecodingService..." << endl; |
2197 | + |
2198 | auto service = std::make_shared<media::ServiceImplementation>(); |
2199 | service->run(); |
2200 | |
2201 | |
2202 | === modified file 'src/core/media/service.cpp' |
2203 | --- src/core/media/service.cpp 2014-01-17 20:58:31 +0000 |
2204 | +++ src/core/media/service.cpp 2014-04-30 01:13:03 +0000 |
2205 | @@ -24,7 +24,7 @@ |
2206 | |
2207 | const std::shared_ptr<media::Service> media::Service::Client::instance() |
2208 | { |
2209 | - std::cout << "Creating a new Service instance" << std::endl; |
2210 | + std::cout << "Creating a new static Service instance" << std::endl; |
2211 | static std::shared_ptr<media::Service> instance{new media::ServiceStub()}; |
2212 | return instance; |
2213 | } |
2214 | |
2215 | === modified file 'src/core/media/service_implementation.cpp' |
2216 | --- src/core/media/service_implementation.cpp 2014-01-13 21:51:14 +0000 |
2217 | +++ src/core/media/service_implementation.cpp 2014-04-30 01:13:03 +0000 |
2218 | @@ -21,21 +21,63 @@ |
2219 | #include "player_configuration.h" |
2220 | #include "player_implementation.h" |
2221 | |
2222 | -#include "gstreamer/engine.h" |
2223 | +#include <map> |
2224 | |
2225 | namespace media = core::ubuntu::media; |
2226 | |
2227 | +using namespace std; |
2228 | + |
2229 | struct media::ServiceImplementation::Private |
2230 | { |
2231 | - Private() : engine(std::make_shared<gstreamer::Engine>()) |
2232 | - { |
2233 | - } |
2234 | - std::shared_ptr<media::Engine> engine; |
2235 | + Private() |
2236 | + : key_(0) |
2237 | + { |
2238 | + } |
2239 | + |
2240 | + void track_player(const std::shared_ptr<media::Player>& player) |
2241 | + { |
2242 | + cout << __PRETTY_FUNCTION__ << endl; |
2243 | + cout << "key: " << key_ << endl; |
2244 | + player_map.insert( |
2245 | + std::pair<media::Player::PlayerKey, |
2246 | + std::shared_ptr<media::Player>>(key_, player)); |
2247 | + |
2248 | + ++key_; |
2249 | + } |
2250 | + |
2251 | + inline media::Player::PlayerKey key() const |
2252 | + { |
2253 | + return key_; |
2254 | + } |
2255 | + |
2256 | + void pause_other_sessions(media::Player::PlayerKey key) |
2257 | + { |
2258 | + cout << __PRETTY_FUNCTION__ << endl; |
2259 | + cout << "key: " << key << endl; |
2260 | + |
2261 | + // TODO: Add a field to Player that is the type of player so that certain |
2262 | + // types of playback aren't paused below. E.g. a camera click sound shouldn't |
2263 | + // pause, nor should it pause background music sessions |
2264 | + for (auto& player_pair : player_map) |
2265 | + { |
2266 | + if (player_pair.second->playback_status() == Player::playing |
2267 | + && player_pair.first != key) |
2268 | + { |
2269 | + cout << "Pausing player with key: " << player_pair.first << endl; |
2270 | + player_pair.second->pause(); |
2271 | + } |
2272 | + } |
2273 | + } |
2274 | + |
2275 | + // Used for Player instance management |
2276 | + std::map<media::Player::PlayerKey, std::shared_ptr<media::Player>> player_map; |
2277 | + media::Player::PlayerKey key_; |
2278 | + |
2279 | }; |
2280 | |
2281 | media::ServiceImplementation::ServiceImplementation() : d(new Private()) |
2282 | { |
2283 | - |
2284 | + cout << __PRETTY_FUNCTION__ << endl; |
2285 | } |
2286 | |
2287 | media::ServiceImplementation::~ServiceImplementation() |
2288 | @@ -45,8 +87,13 @@ |
2289 | std::shared_ptr<media::Player> media::ServiceImplementation::create_session( |
2290 | const media::Player::Configuration& conf) |
2291 | { |
2292 | - return std::make_shared<media::PlayerImplementation>( |
2293 | - conf.object_path, |
2294 | - shared_from_this(), |
2295 | - d->engine); |
2296 | + std::shared_ptr<media::Player> player = std::make_shared<media::PlayerImplementation>( |
2297 | + conf.object_path, shared_from_this(), d->key()); |
2298 | + d->track_player(player); |
2299 | + return player; |
2300 | +} |
2301 | + |
2302 | +void media::ServiceImplementation::pause_other_sessions(media::Player::PlayerKey key) |
2303 | +{ |
2304 | + d->pause_other_sessions(key); |
2305 | } |
2306 | |
2307 | === modified file 'src/core/media/service_implementation.h' |
2308 | --- src/core/media/service_implementation.h 2014-01-13 21:51:14 +0000 |
2309 | +++ src/core/media/service_implementation.h 2014-04-30 01:13:03 +0000 |
2310 | @@ -27,6 +27,9 @@ |
2311 | { |
2312 | namespace media |
2313 | { |
2314 | + |
2315 | +class Player; |
2316 | + |
2317 | class ServiceImplementation : public ServiceSkeleton |
2318 | { |
2319 | public: |
2320 | @@ -35,6 +38,8 @@ |
2321 | |
2322 | std::shared_ptr<Player> create_session(const Player::Configuration&); |
2323 | |
2324 | + void pause_other_sessions(Player::PlayerKey key); |
2325 | + |
2326 | private: |
2327 | struct Private; |
2328 | std::shared_ptr<Private> d; |
2329 | |
2330 | === modified file 'src/core/media/service_skeleton.cpp' |
2331 | --- src/core/media/service_skeleton.cpp 2014-02-12 15:53:57 +0000 |
2332 | +++ src/core/media/service_skeleton.cpp 2014-04-30 01:13:03 +0000 |
2333 | @@ -1,5 +1,5 @@ |
2334 | /* |
2335 | - * Copyright © 2013 Canonical Ltd. |
2336 | + * Copyright © 2013-2014 Canonical Ltd. |
2337 | * |
2338 | * This program is free software: you can redistribute it and/or modify it |
2339 | * under the terms of the GNU Lesser General Public License version 3, |
2340 | @@ -49,6 +49,11 @@ |
2341 | &Private::handle_create_session, |
2342 | this, |
2343 | std::placeholders::_1)); |
2344 | + object->install_method_handler<mpris::Service::PauseOtherSessions>( |
2345 | + std::bind( |
2346 | + &Private::handle_pause_other_sessions, |
2347 | + this, |
2348 | + std::placeholders::_1)); |
2349 | } |
2350 | |
2351 | void handle_create_session(const core::dbus::Message::Ptr& msg) |
2352 | @@ -86,6 +91,17 @@ |
2353 | } |
2354 | } |
2355 | |
2356 | + void handle_pause_other_sessions(const core::dbus::Message::Ptr& msg) |
2357 | + { |
2358 | + std::cout << __PRETTY_FUNCTION__ << std::endl; |
2359 | + Player::PlayerKey key; |
2360 | + msg->reader() >> key; |
2361 | + impl->pause_other_sessions(key); |
2362 | + |
2363 | + auto reply = dbus::Message::make_method_return(msg); |
2364 | + impl->access_bus()->send(reply); |
2365 | + } |
2366 | + |
2367 | media::ServiceSkeleton* impl; |
2368 | dbus::Object::Ptr object; |
2369 | |
2370 | |
2371 | === modified file 'src/core/media/service_skeleton.h' |
2372 | --- src/core/media/service_skeleton.h 2014-02-12 15:53:57 +0000 |
2373 | +++ src/core/media/service_skeleton.h 2014-04-30 01:13:03 +0000 |
2374 | @@ -1,5 +1,5 @@ |
2375 | /* |
2376 | - * Copyright © 2013 Canonical Ltd. |
2377 | + * Copyright © 2013-2014 Canonical Ltd. |
2378 | * |
2379 | * This program is free software: you can redistribute it and/or modify it |
2380 | * under the terms of the GNU Lesser General Public License version 3, |
2381 | |
2382 | === modified file 'src/core/media/service_stub.cpp' |
2383 | --- src/core/media/service_stub.cpp 2014-02-12 15:53:57 +0000 |
2384 | +++ src/core/media/service_stub.cpp 2014-04-30 01:13:03 +0000 |
2385 | @@ -1,5 +1,5 @@ |
2386 | /* |
2387 | - * Copyright © 2013 Canonical Ltd. |
2388 | + * Copyright © 2013-2014 Canonical Ltd. |
2389 | * |
2390 | * This program is free software: you can redistribute it and/or modify it |
2391 | * under the terms of the GNU Lesser General Public License version 3, |
2392 | @@ -47,13 +47,21 @@ |
2393 | |
2394 | std::shared_ptr<media::Player> media::ServiceStub::create_session(const media::Player::Configuration&) |
2395 | { |
2396 | - auto op |
2397 | - = d->object->invoke_method_synchronously< |
2398 | - mpris::Service::CreateSession, |
2399 | - dbus::types::ObjectPath>(); |
2400 | + auto op = d->object->invoke_method_synchronously<mpris::Service::CreateSession, |
2401 | + dbus::types::ObjectPath>(); |
2402 | |
2403 | if (op.is_error()) |
2404 | throw std::runtime_error("Problem creating session: " + op.error()); |
2405 | |
2406 | return std::shared_ptr<media::Player>(new media::PlayerStub(shared_from_this(), op.value())); |
2407 | } |
2408 | + |
2409 | +void media::ServiceStub::pause_other_sessions(media::Player::PlayerKey key) |
2410 | +{ |
2411 | + std::cout << __PRETTY_FUNCTION__ << std::endl; |
2412 | + auto op = d->object->invoke_method_synchronously<mpris::Service::PauseOtherSessions, |
2413 | + void>(key); |
2414 | + |
2415 | + if (op.is_error()) |
2416 | + throw std::runtime_error("Problem pausing other sessions: " + op.error()); |
2417 | +} |
2418 | |
2419 | === modified file 'src/core/media/service_stub.h' |
2420 | --- src/core/media/service_stub.h 2014-02-12 15:53:57 +0000 |
2421 | +++ src/core/media/service_stub.h 2014-04-30 01:13:03 +0000 |
2422 | @@ -1,5 +1,5 @@ |
2423 | /* |
2424 | - * Copyright © 2013 Canonical Ltd. |
2425 | + * Copyright © 2013-2014 Canonical Ltd. |
2426 | * |
2427 | * This program is free software: you can redistribute it and/or modify it |
2428 | * under the terms of the GNU Lesser General Public License version 3, |
2429 | @@ -40,6 +40,7 @@ |
2430 | ~ServiceStub(); |
2431 | |
2432 | std::shared_ptr<Player> create_session(const Player::Configuration&); |
2433 | + void pause_other_sessions(Player::PlayerKey key); |
2434 | |
2435 | private: |
2436 | struct Private; |
2437 | |
2438 | === modified file 'src/core/media/track_list_implementation.cpp' |
2439 | --- src/core/media/track_list_implementation.cpp 2014-02-12 15:53:57 +0000 |
2440 | +++ src/core/media/track_list_implementation.cpp 2014-04-30 01:13:03 +0000 |
2441 | @@ -16,6 +16,9 @@ |
2442 | * Authored by: Thomas Voß <thomas.voss@canonical.com> |
2443 | */ |
2444 | |
2445 | +#include <stdio.h> |
2446 | +#include <stdlib.h> |
2447 | + |
2448 | #include "track_list_implementation.h" |
2449 | |
2450 | #include "engine.h" |
2451 | @@ -45,6 +48,16 @@ |
2452 | { |
2453 | } |
2454 | |
2455 | +media::Track::UriType media::TrackListImplementation::query_uri_for_track(const media::Track::Id& id) |
2456 | +{ |
2457 | + auto it = d->meta_data_cache.find(id); |
2458 | + |
2459 | + if (it == d->meta_data_cache.end()) |
2460 | + return Track::UriType{}; |
2461 | + |
2462 | + return std::get<0>(it->second); |
2463 | +} |
2464 | + |
2465 | media::Track::MetaData media::TrackListImplementation::query_meta_data_for_track(const media::Track::Id& id) |
2466 | { |
2467 | auto it = d->meta_data_cache.find(id); |
2468 | |
2469 | === modified file 'src/core/media/track_list_implementation.h' |
2470 | --- src/core/media/track_list_implementation.h 2014-02-12 15:53:57 +0000 |
2471 | +++ src/core/media/track_list_implementation.h 2014-04-30 01:13:03 +0000 |
2472 | @@ -36,6 +36,7 @@ |
2473 | const std::shared_ptr<Engine::MetaDataExtractor>& extractor); |
2474 | ~TrackListImplementation(); |
2475 | |
2476 | + Track::UriType query_uri_for_track(const Track::Id& id); |
2477 | Track::MetaData query_meta_data_for_track(const Track::Id& id); |
2478 | |
2479 | void add_track_with_uri_at(const Track::UriType& uri, const Track::Id& position, bool make_current); |
2480 | |
2481 | === modified file 'src/core/media/track_list_skeleton.cpp' |
2482 | --- src/core/media/track_list_skeleton.cpp 2014-02-12 15:53:57 +0000 |
2483 | +++ src/core/media/track_list_skeleton.cpp 2014-04-30 01:13:03 +0000 |
2484 | @@ -48,7 +48,8 @@ |
2485 | object(object), |
2486 | can_edit_tracks(object->get_property<mpris::TrackList::Properties::CanEditTracks>()), |
2487 | tracks(object->get_property<mpris::TrackList::Properties::Tracks>()), |
2488 | - current_track(tracks->get().begin()) |
2489 | + current_track(tracks->get().begin()), |
2490 | + empty_iterator(tracks->get().begin()) |
2491 | { |
2492 | } |
2493 | |
2494 | @@ -103,6 +104,7 @@ |
2495 | std::shared_ptr<core::dbus::Property<mpris::TrackList::Properties::CanEditTracks>> can_edit_tracks; |
2496 | std::shared_ptr<core::dbus::Property<mpris::TrackList::Properties::Tracks>> tracks; |
2497 | TrackList::ConstIterator current_track; |
2498 | + TrackList::ConstIterator empty_iterator; |
2499 | |
2500 | core::Signal<void> on_track_list_replaced; |
2501 | core::Signal<Track::Id> on_track_added; |
2502 | @@ -142,12 +144,22 @@ |
2503 | |
2504 | bool media::TrackListSkeleton::has_next() const |
2505 | { |
2506 | - return std::next(d->current_track) != d->tracks->get().end(); |
2507 | + return d->current_track != d->tracks->get().end(); |
2508 | } |
2509 | |
2510 | const media::Track::Id& media::TrackListSkeleton::next() |
2511 | { |
2512 | - return *(d->current_track = std::next(d->current_track)); |
2513 | + if (d->tracks->get().empty()) |
2514 | + return *(d->current_track); |
2515 | + |
2516 | + if (d->tracks->get().size() && (d->current_track == d->empty_iterator)) |
2517 | + { |
2518 | + d->current_track = d->tracks->get().begin(); |
2519 | + return *(d->current_track = std::next(d->current_track)); |
2520 | + } |
2521 | + |
2522 | + d->current_track = std::next(d->current_track); |
2523 | + return *(d->current_track); |
2524 | } |
2525 | |
2526 | const core::Property<bool>& media::TrackListSkeleton::can_edit_tracks() const |
2527 | |
2528 | === modified file 'src/core/media/track_list_skeleton.h' |
2529 | --- src/core/media/track_list_skeleton.h 2014-02-12 15:53:57 +0000 |
2530 | +++ src/core/media/track_list_skeleton.h 2014-04-30 01:13:03 +0000 |
2531 | @@ -48,9 +48,10 @@ |
2532 | const core::Signal<Track::Id>& on_track_removed() const; |
2533 | const core::Signal<Track::Id>& on_track_changed() const; |
2534 | |
2535 | + core::Property<Container>& tracks(); |
2536 | + |
2537 | protected: |
2538 | core::Property<bool>& can_edit_tracks(); |
2539 | - core::Property<Container>& tracks(); |
2540 | |
2541 | core::Signal<void>& on_track_list_replaced(); |
2542 | core::Signal<Track::Id>& on_track_added(); |
2543 | |
2544 | === modified file 'tests/acceptance-tests/service.cpp' |
2545 | --- tests/acceptance-tests/service.cpp 2014-03-06 19:23:19 +0000 |
2546 | +++ tests/acceptance-tests/service.cpp 2014-04-30 01:13:03 +0000 |
2547 | @@ -1,5 +1,5 @@ |
2548 | /* |
2549 | - * Copyright © 2013 Canonical Ltd. |
2550 | + * Copyright © 2013-2014 Canonical Ltd. |
2551 | * |
2552 | * This program is free software: you can redistribute it and/or modify it |
2553 | * under the terms of the GNU Lesser General Public License version 3, |
2554 | |
2555 | === modified file 'tests/unit-tests/CMakeLists.txt' |
2556 | --- tests/unit-tests/CMakeLists.txt 2014-01-17 20:58:31 +0000 |
2557 | +++ tests/unit-tests/CMakeLists.txt 2014-04-30 01:13:03 +0000 |
2558 | @@ -1,10 +1,21 @@ |
2559 | include_directories( |
2560 | . |
2561 | ${CMAKE_SOURCE_DIR}/src |
2562 | + ${PC_GSTREAMER_1_0_INCLUDE_DIRS} |
2563 | ) |
2564 | |
2565 | add_executable( |
2566 | test-gstreamer-engine |
2567 | + |
2568 | + libmedia-mock.cpp |
2569 | + ${CMAKE_SOURCE_DIR}/src/core/media/engine.cpp |
2570 | + ${CMAKE_SOURCE_DIR}/src/core/media/gstreamer/engine.cpp |
2571 | + ${CMAKE_SOURCE_DIR}/src/core/media/player_skeleton.cpp |
2572 | + ${CMAKE_SOURCE_DIR}/src/core/media/player_implementation.cpp |
2573 | + ${CMAKE_SOURCE_DIR}/src/core/media/service_skeleton.cpp |
2574 | + ${CMAKE_SOURCE_DIR}/src/core/media/service_implementation.cpp |
2575 | + ${CMAKE_SOURCE_DIR}/src/core/media/track_list_skeleton.cpp |
2576 | + ${CMAKE_SOURCE_DIR}/src/core/media/track_list_implementation.cpp |
2577 | test-gstreamer-engine.cpp |
2578 | ) |
2579 | |
2580 | @@ -13,12 +24,15 @@ |
2581 | |
2582 | media-hub-common |
2583 | media-hub-client |
2584 | - media-hub-service |
2585 | media-hub-test-framework |
2586 | |
2587 | ${CMAKE_THREAD_LIBS_INIT} |
2588 | ${Boost_LIBRARIES} |
2589 | ${DBUS_LIBRARIES} |
2590 | + ${DBUS_CPP_LDFLAGS} |
2591 | + ${GLog_LIBRARY} |
2592 | + ${PC_GSTREAMER_1_0_LIBRARIES} |
2593 | + ${GIO_LIBRARIES} |
2594 | |
2595 | gmock |
2596 | gmock_main |
2597 | |
2598 | === added file 'tests/unit-tests/libmedia-mock.cpp' |
2599 | --- tests/unit-tests/libmedia-mock.cpp 1970-01-01 00:00:00 +0000 |
2600 | +++ tests/unit-tests/libmedia-mock.cpp 2014-04-30 01:13:03 +0000 |
2601 | @@ -0,0 +1,26 @@ |
2602 | +/* |
2603 | + * Copyright © 2013-2014 Canonical Ltd. |
2604 | + * |
2605 | + * This program is free software: you can redistribute it and/or modify it |
2606 | + * under the terms of the GNU Lesser General Public License version 3, |
2607 | + * as published by the Free Software Foundation. |
2608 | + * |
2609 | + * This program is distributed in the hope that it will be useful, |
2610 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2611 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2612 | + * GNU Lesser General Public License for more details. |
2613 | + * |
2614 | + * You should have received a copy of the GNU Lesser General Public License |
2615 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2616 | + * |
2617 | + * Authored by: Jim Hodapp <jim.hodapp@canonical.com> |
2618 | + */ |
2619 | + |
2620 | +#include <hybris/media/media_codec_layer.h> |
2621 | +#include <hybris/media/surface_texture_client_hybris.h> |
2622 | + |
2623 | +#define UNUSED __attribute__((unused)) |
2624 | + |
2625 | +void decoding_service_set_client_death_cb(UNUSED DecodingClientDeathCbHybris callback, UNUSED void *context) |
2626 | +{ |
2627 | +} |
2628 | |
2629 | === modified file 'tests/unit-tests/test-gstreamer-engine.cpp' |
2630 | --- tests/unit-tests/test-gstreamer-engine.cpp 2014-02-26 14:58:36 +0000 |
2631 | +++ tests/unit-tests/test-gstreamer-engine.cpp 2014-04-30 01:13:03 +0000 |
2632 | @@ -1,5 +1,5 @@ |
2633 | /* |
2634 | - * Copyright © 2013 Canonical Ltd. |
2635 | + * Copyright © 2013-2014 Canonical Ltd. |
2636 | * |
2637 | * This program is free software: you can redistribute it and/or modify it |
2638 | * under the terms of the GNU Lesser General Public License version 3, |
2639 | @@ -198,7 +198,7 @@ |
2640 | std::chrono::seconds{40})); |
2641 | } |
2642 | |
2643 | -TEST(GStreamerEngine, DISABLED_stop_pause_play_seek_video_works) |
2644 | +TEST(GStreamerEngine, stop_pause_play_seek_video_works) |
2645 | { |
2646 | const std::string test_file{"/tmp/h264.avi"}; |
2647 | const std::string test_file_uri{"file:///tmp/h264.avi"}; |
2648 | @@ -248,8 +248,8 @@ |
2649 | |
2650 | TEST(GStreamerEngine, get_position_duration_work) |
2651 | { |
2652 | - const std::string test_file{"/tmp/test.ogg"}; |
2653 | - const std::string test_file_uri{"file:///tmp/test.ogg"}; |
2654 | + const std::string test_file{"/tmp/h264.avi"}; |
2655 | + const std::string test_file_uri{"file:///tmp/h264.avi"}; |
2656 | std::remove(test_file.c_str()); |
2657 | ASSERT_TRUE(test::copy_test_ogg_file_to(test_file)); |
2658 | |
2659 | @@ -269,10 +269,18 @@ |
2660 | EXPECT_TRUE(wst.wait_for_state_for( |
2661 | core::ubuntu::media::Engine::State::playing, |
2662 | std::chrono::milliseconds{4000})); |
2663 | - sleep(1); |
2664 | - |
2665 | - // FIXME: Ideally we want to seek_to and measure the position there, but seek_to seems |
2666 | - // broken from within this unit test |
2667 | + |
2668 | + EXPECT_TRUE(engine.seek_to(std::chrono::seconds{10})); |
2669 | + EXPECT_TRUE(engine.play()); |
2670 | + EXPECT_TRUE(wst.wait_for_state_for( |
2671 | + core::ubuntu::media::Engine::State::playing, |
2672 | + std::chrono::milliseconds{4000})); |
2673 | + |
2674 | + std::cout << "position: " << engine.position() << std::endl; |
2675 | + std::cout << "duration: " << engine.duration() << std::endl; |
2676 | + |
2677 | + // FIXME: This should be 10e9, but seek_to seems to be broken from within this unit test |
2678 | + // and I haven't been able to figure out why |
2679 | EXPECT_TRUE(engine.position() > 1e9); |
2680 | |
2681 | EXPECT_TRUE(engine.duration() > 1e9); |
FAILED: Continuous integration, rev:30 jenkins. qa.ubuntu. com/job/ media-hub- ci/59/ jenkins. qa.ubuntu. com/job/ media-hub- trusty- amd64-ci/ 60/console jenkins. qa.ubuntu. com/job/ media-hub- trusty- armhf-ci/ 59/console jenkins. qa.ubuntu. com/job/ media-hub- trusty- i386-ci/ 59/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/media- hub-ci/ 59/rebuild
http://