Merge lp:~phablet-team/media-hub/video-support into lp:media-hub
- video-support
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 28 |
Proposed branch: | lp:~phablet-team/media-hub/video-support |
Merge into: | lp:media-hub |
Prerequisite: | lp:~sergiusens/media-hub/packaging |
Diff against target: |
2005 lines (+1032/-65) 30 files modified
CMakeLists.txt (+2/-0) debian/control (+3/-0) debian/media-hub.conf (+1/-1) debian/media-hub.install (+1/-0) debian/rules (+4/-0) debian/usr.bin.media-hub-server (+98/-0) include/core/media/player.h (+15/-3) src/core/media/CMakeLists.txt (+6/-2) src/core/media/apparmor.h (+51/-0) src/core/media/engine.h (+8/-0) src/core/media/gstreamer/engine.cpp (+86/-8) src/core/media/gstreamer/engine.h (+8/-0) src/core/media/gstreamer/playbin.h (+181/-20) src/core/media/mpris/player.h (+4/-0) src/core/media/player_implementation.cpp (+64/-7) src/core/media/player_implementation.h (+4/-0) src/core/media/player_skeleton.cpp (+192/-6) src/core/media/player_skeleton.h (+10/-0) src/core/media/player_stub.cpp (+167/-3) src/core/media/player_stub.h (+9/-0) src/core/media/server/server.cpp (+28/-0) src/core/media/service.cpp (+1/-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/video-support |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Needs Fixing | |
Ricardo Mendoza (community) | Needs Fixing | ||
Jamie Strandboge | Pending | ||
Ubuntu Phablet Team | code | Pending | |
Review via email: mp+212905@code.launchpad.net |
This proposal supersedes a proposal from 2014-03-26.
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
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
PS Jenkins bot (ps-jenkins) wrote : | # |
- 37. By Jim Hodapp
-
Merged with Sergio's packaging changes. Added a copyright header to server.cpp. Removed any includes for decoding_service.h since it's not being used right now.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:37
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 38. By Jim Hodapp
-
Didn't mean to #include <visibility.h> in previous commit, undo that.
- 39. By Jim Hodapp
-
Enable libhyris-dev as a build-dep
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:39
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 40. By Jim Hodapp
-
Get rid of the visibility attribute.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:40
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:41
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 41. By Jim Hodapp
-
Add libproperties-
cpp-dev as a Depends: for libmedia-hub-dev - 42. By Jim Hodapp
-
Merged with upstream changes to disable all unit-tests
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:42
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Ricardo Mendoza (ricmm) wrote : | # |
91 +include_
99 + -lmedia
libmedia-dev ships a pkg config file for this
495 + std::cout << "IGBPWrapperHybris: " << igbp << std::endl;
496 + SurfaceTextureC
497 + std::cout << "SurfaceTexture
Those couts are probably not needed anymore, even if we are keeping a good chunk of debug info
863 + seeked_
864 + {
865 + std::cout << "value: " << value << std::endl;
866 + //dbus.
867 + });
Lets try and get rid of those ^
1166 + throw std::runtime_
Odd error message from context
- 43. By Jim Hodapp
-
Made ricmm's change recommendations and enabled the tests that still work properly.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:43
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 44. By Jim Hodapp
-
Snap to the preceeding key unit after doing a seek.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:44
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 45. By Jim Hodapp
-
Mock decoding_
service_ set_client_ death_cb so that the unittests don't crash when running on a non-target device.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:45
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 46. By Jim Hodapp
-
Enable the seeked_to signal
- 47. By Jim Hodapp
-
Merged with ricmm's EOS fix branch
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:47
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 48. By Jim Hodapp
-
Initial version of apparmor security context arbitration for open_uri. This does not yet check the trust store
- 49. By Jim Hodapp
-
Refine the apparmor arbitration a bit. Whitelist music-app explicitly until the trust store lands.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:48
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:49
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 50. By Jim Hodapp
-
Only start when dbus is started instead of preventing media-hub from being able to be stopped
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:50
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 51. By Jim Hodapp
-
Enable streaming sources to work with media-hub
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:51
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 52. By Jim Hodapp
-
Allow apps to access their own media files in /opt
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:52
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 53. By Jim Hodapp
-
Merged with jdstrand's changes to confine media-hub with apparmor
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:53
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 54. By Jim Hodapp
-
Slightly improve the get_position_
duration_ works unit test
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:54
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 55. By Jim Hodapp
-
Make sure the camer-app can play the click sound when a user captures a picture
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:55
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-17 21:13:23 +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-17 21:13:23 +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-17 21:13:23 +0000 |
45 | @@ -1,6 +1,6 @@ |
46 | description "Starts the media-hub service" |
47 | |
48 | -start on dbus |
49 | +start on started dbus |
50 | stop on runlevel [06] |
51 | |
52 | exec media-hub-server |
53 | |
54 | === modified file 'debian/media-hub.install' |
55 | --- debian/media-hub.install 2014-03-06 22:51:51 +0000 |
56 | +++ debian/media-hub.install 2014-04-17 21:13:23 +0000 |
57 | @@ -1,2 +1,3 @@ |
58 | debian/media-hub.conf /usr/share/upstart/sessions/ |
59 | +debian/usr.bin.media-hub-server etc/apparmor.d |
60 | usr/bin |
61 | |
62 | === modified file 'debian/rules' |
63 | --- debian/rules 2014-03-07 22:49:23 +0000 |
64 | +++ debian/rules 2014-04-17 21:13:23 +0000 |
65 | @@ -14,3 +14,7 @@ |
66 | |
67 | override_dh_auto_test: |
68 | env -u LD_PRELOAD dh_auto_test |
69 | + |
70 | +override_dh_installdeb: |
71 | + dh_apparmor --profile-name=usr.bin.media-hub-server -pmedia-hub |
72 | + dh_installdeb |
73 | |
74 | === added file 'debian/usr.bin.media-hub-server' |
75 | --- debian/usr.bin.media-hub-server 1970-01-01 00:00:00 +0000 |
76 | +++ debian/usr.bin.media-hub-server 2014-04-17 21:13:23 +0000 |
77 | @@ -0,0 +1,98 @@ |
78 | +#include <tunables/global> |
79 | + |
80 | +/usr/bin/media-hub-server (attach_disconnected) { |
81 | + #include <abstractions/base> |
82 | + #include <abstractions/audio> |
83 | + #include <abstractions/nameservice> |
84 | + #include <abstractions/dbus-session> |
85 | + #include <abstractions/dbus-strict> |
86 | + #include <abstractions/user-tmp> |
87 | + #include "/usr/share/apparmor/hardware/audio.d" |
88 | + #include "/usr/share/apparmor/hardware/graphics.d" |
89 | + #include "/usr/share/apparmor/hardware/video.d" |
90 | + |
91 | + deny /dev/cpuctl/apps/tasks w, |
92 | + deny /dev/cpuctl/apps/bg_non_interactive/tasks w, |
93 | + |
94 | + @{PROC}/interrupts r, |
95 | + owner @{PROC}/cmdline r, |
96 | + owner @{PROC}/[0-9]*/auxv r, |
97 | + owner @{PROC}/[0-9]*/fd/ r, |
98 | + owner @{PROC}/[0-9]*/status r, |
99 | + owner @{PROC}/[0-9]*/task/ r, |
100 | + owner @{PROC}/[0-9]*/task/[0-9]*/ r, |
101 | + owner @{PROC}/[0-9]*/cmdline r, |
102 | + |
103 | + /sys/kernel/debug/tracing/trace_marker w, |
104 | + /dev/ashmem rw, |
105 | + |
106 | + # Explicitly deny this-- it is not needed |
107 | + /dev/fb0 rw, |
108 | + |
109 | + # libhybris |
110 | + /{,var/}run/shm/hybris_shm_data rw, |
111 | + /usr/lib/@{multiarch}/libhybris/*.so mr, |
112 | + /{,android/}system/build.prop r, |
113 | + # These libraries can be in any of: |
114 | + # /vendor/lib |
115 | + # /system/lib |
116 | + # /system/vendor/lib |
117 | + # /android/vendor/lib |
118 | + # /android/system/lib |
119 | + # /android/system/vendor/lib |
120 | + /{,android/}vendor/lib/** r, |
121 | + /{,android/}vendor/lib/**.so m, |
122 | + /{,android/}system/lib/** r, |
123 | + /{,android/}system/lib/**.so m, |
124 | + /{,android/}system/vendor/lib/** r, |
125 | + /{,android/}system/vendor/lib/**.so m, |
126 | + |
127 | + # attach_disconnected path |
128 | + /dev/socket/property_service rw, |
129 | + |
130 | + # Android logging triggered by platform. Can safely deny |
131 | + deny /dev/log_main w, |
132 | + deny /dev/log_radio w, |
133 | + deny /dev/log_events w, |
134 | + deny /dev/log_system w, |
135 | + |
136 | + # Allow all access to powerd for now, but we can fine-tune this if needed |
137 | + dbus (receive, send) |
138 | + bus=system |
139 | + path=/com/canonical/powerd |
140 | + interface=com.canonical.powerd, |
141 | + |
142 | + # GStreamer binary registry - hybris pulls this in for everything now, not |
143 | + # just audio |
144 | + owner @{HOME}/.gstreamer*/registry.*.bin* rw, |
145 | + owner @{HOME}/.gstreamer*/ rw, |
146 | + owner @{HOME}/.cache/gstreamer*/registry.*.bin* rw, |
147 | + |
148 | + /{,android/}system/etc/media_codecs.xml r, |
149 | + /etc/wildmidi/wildmidi.cfg r, |
150 | + |
151 | + audit deny owner /** m, |
152 | + |
153 | + # Allow read on all directories |
154 | + /**/ r, |
155 | + |
156 | + # Allow read on click install directories, removable media and files in |
157 | + # /usr/local/share. |
158 | + /usr/share/** r, |
159 | + /usr/local/share/** r, |
160 | + /{media,mnt,opt,srv}/** r, |
161 | + |
162 | + # Allow reading any files in non-hidden directories |
163 | + owner @{HOME}/[^.]* rk, |
164 | + owner @{HOME}/[^.]*/ rk, |
165 | + owner @{HOME}/[^.]*/** rk, |
166 | + |
167 | + # Allow reading files in XDG directories (ie, where apps are allowed to |
168 | + # write) |
169 | + owner @{HOME}/.cache/** rk, |
170 | + owner @{HOME}/.local/share/** rk, |
171 | + owner /{,var/}run/user/[0-9]*/** rk, |
172 | + |
173 | + # Site-specific additions and overrides. See local/README for details. |
174 | + #include <local/usr.bin.media-hub-server> |
175 | +} |
176 | |
177 | === modified file 'include/core/media/player.h' |
178 | --- include/core/media/player.h 2014-02-18 19:27:01 +0000 |
179 | +++ include/core/media/player.h 2014-04-17 21:13:23 +0000 |
180 | @@ -39,6 +39,12 @@ |
181 | public: |
182 | typedef double PlaybackRate; |
183 | typedef double Volume; |
184 | + typedef void* GLConsumerWrapperHybris; |
185 | + |
186 | + /** Used to set a callback function to be called when a frame is ready to be rendered **/ |
187 | + typedef void (*FrameAvailableCbHybris)(GLConsumerWrapperHybris wrapper, void *context); |
188 | + typedef void (*FrameAvailableCb)(void *context); |
189 | + typedef void (*PlaybackCompleteCb)(void *context); |
190 | |
191 | struct Configuration; |
192 | |
193 | @@ -74,6 +80,8 @@ |
194 | virtual std::shared_ptr<TrackList> track_list() = 0; |
195 | |
196 | virtual bool open_uri(const Track::UriType& uri) = 0; |
197 | + virtual void create_video_sink(uint32_t texture_id) = 0; |
198 | + virtual GLConsumerWrapperHybris gl_consumer() const = 0; |
199 | virtual void next() = 0; |
200 | virtual void previous() = 0; |
201 | virtual void play() = 0; |
202 | @@ -81,11 +89,17 @@ |
203 | virtual void stop() = 0; |
204 | virtual void seek_to(const std::chrono::microseconds& offset) = 0; |
205 | |
206 | + // TODO: Convert this to be a signal |
207 | + virtual void set_frame_available_callback(FrameAvailableCb cb, void *context) = 0; |
208 | + virtual void set_playback_complete_callback(PlaybackCompleteCb cb, void *context) = 0; |
209 | + |
210 | virtual const core::Property<bool>& can_play() const = 0; |
211 | virtual const core::Property<bool>& can_pause() const = 0; |
212 | virtual const core::Property<bool>& can_seek() const = 0; |
213 | virtual const core::Property<bool>& can_go_previous() const = 0; |
214 | virtual const core::Property<bool>& can_go_next() const = 0; |
215 | + virtual const core::Property<bool>& is_video_source() const = 0; |
216 | + virtual const core::Property<bool>& is_audio_source() const = 0; |
217 | virtual const core::Property<PlaybackStatus>& playback_status() const = 0; |
218 | virtual const core::Property<LoopStatus>& loop_status() const = 0; |
219 | virtual const core::Property<PlaybackRate>& playback_rate() const = 0; |
220 | @@ -97,15 +111,13 @@ |
221 | virtual const core::Property<uint64_t>& position() const = 0; |
222 | virtual const core::Property<uint64_t>& duration() const = 0; |
223 | |
224 | - |
225 | virtual core::Property<LoopStatus>& loop_status() = 0; |
226 | virtual core::Property<PlaybackRate>& playback_rate() = 0; |
227 | virtual core::Property<bool>& is_shuffle() = 0; |
228 | virtual core::Property<Volume>& volume() = 0; |
229 | |
230 | - |
231 | virtual const core::Signal<uint64_t>& seeked_to() const = 0; |
232 | - |
233 | + virtual const core::Signal<void>& end_of_stream() const = 0; |
234 | protected: |
235 | Player(); |
236 | |
237 | |
238 | === modified file 'src/core/media/CMakeLists.txt' |
239 | --- src/core/media/CMakeLists.txt 2014-02-26 14:58:36 +0000 |
240 | +++ src/core/media/CMakeLists.txt 2014-04-17 21:13:23 +0000 |
241 | @@ -1,6 +1,6 @@ |
242 | pkg_check_modules(PC_GSTREAMER_1_0 REQUIRED gstreamer-1.0) |
243 | |
244 | -include_directories(${PC_GSTREAMER_1_0_INCLUDE_DIRS}) |
245 | +include_directories(${PC_GSTREAMER_1_0_INCLUDE_DIRS} ${HYBRIS_MEDIA_CFLAGS}) |
246 | |
247 | add_library( |
248 | media-hub-common SHARED |
249 | @@ -52,6 +52,7 @@ |
250 | ${DBUS_LIBRARIES} |
251 | ${DBUS_CPP_LDFLAGS} |
252 | ${GLog_LIBRARY} |
253 | + ${HYBRIS_MEDIA_LIBRARIES} |
254 | ) |
255 | |
256 | install( |
257 | @@ -82,9 +83,11 @@ |
258 | ${DBUS_CPP_LDFLAGS} |
259 | ${GLog_LIBRARY} |
260 | ${PC_GSTREAMER_1_0_LIBRARIES} |
261 | + ${GIO_LIBRARIES} |
262 | + ${HYBRIS_MEDIA_LIBRARIES} |
263 | ) |
264 | |
265 | -include_directories(${PROJECT_SOURCE_DIR}/src/) |
266 | +include_directories(${PROJECT_SOURCE_DIR}/src/ ${HYBRIS_MEDIA_CFLAGS}) |
267 | |
268 | add_executable( |
269 | media-hub-server |
270 | @@ -102,6 +105,7 @@ |
271 | ${DBUS_CPP_LDFLAGS} |
272 | ${GLog_LIBRARY} |
273 | ${PC_GSTREAMER_1_0_LIBRARIES} |
274 | + ${HYBRIS_MEDIA_LIBRARIES} |
275 | ) |
276 | |
277 | install( |
278 | |
279 | === added file 'src/core/media/apparmor.h' |
280 | --- src/core/media/apparmor.h 1970-01-01 00:00:00 +0000 |
281 | +++ src/core/media/apparmor.h 2014-04-17 21:13:23 +0000 |
282 | @@ -0,0 +1,51 @@ |
283 | +/* |
284 | + * Copyright (C) 2013-2014 Canonical Ltd |
285 | + * |
286 | + * This program is free software: you can redistribute it and/or modify |
287 | + * it under the terms of the GNU Lesser General Public License version 3 as |
288 | + * published by the Free Software Foundation. |
289 | + * |
290 | + * This program is distributed in the hope that it will be useful, |
291 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
292 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
293 | + * GNU Lesser General Public License for more details. |
294 | + * |
295 | + * You should have received a copy of the GNU Lesser General Public License |
296 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
297 | + * |
298 | + * Author: Ricardo Mendoza <ricardo.mendoza@canonical.com> |
299 | + */ |
300 | + |
301 | +#ifndef APPARMOR_H_DBUS_ |
302 | +#define APPARMOR_H_DBUS_ |
303 | + |
304 | +#include <string> |
305 | +#include <chrono> |
306 | + |
307 | +namespace core |
308 | +{ |
309 | + |
310 | +struct Apparmor |
311 | +{ |
312 | + static std::string& name() |
313 | + { |
314 | + static std::string s = "org.freedesktop.DBus"; |
315 | + return s; |
316 | + } |
317 | + |
318 | + struct getConnectionAppArmorSecurityContext |
319 | + { |
320 | + static std::string name() |
321 | + { |
322 | + static std::string s = "GetConnectionAppArmorSecurityContext"; |
323 | + return s; |
324 | + } |
325 | + |
326 | + static const std::chrono::milliseconds default_timeout() { return std::chrono::seconds{1}; } |
327 | + |
328 | + typedef Apparmor Interface; |
329 | + }; |
330 | +}; |
331 | +} |
332 | + |
333 | +#endif |
334 | |
335 | === modified file 'src/core/media/engine.h' |
336 | --- src/core/media/engine.h 2014-02-18 19:27:01 +0000 |
337 | +++ src/core/media/engine.h 2014-04-17 21:13:23 +0000 |
338 | @@ -97,12 +97,16 @@ |
339 | virtual const core::Property<State>& state() const = 0; |
340 | |
341 | virtual bool open_resource_for_uri(const Track::UriType& uri) = 0; |
342 | + virtual void create_video_sink(uint32_t texture_id) = 0; |
343 | |
344 | virtual bool play() = 0; |
345 | virtual bool stop() = 0; |
346 | virtual bool pause() = 0; |
347 | virtual bool seek_to(const std::chrono::microseconds& ts) = 0; |
348 | |
349 | + virtual const core::Property<bool>& is_video_source() const = 0; |
350 | + virtual const core::Property<bool>& is_audio_source() const = 0; |
351 | + |
352 | virtual const core::Property<uint64_t>& position() const = 0; |
353 | virtual const core::Property<uint64_t>& duration() const = 0; |
354 | |
355 | @@ -110,6 +114,10 @@ |
356 | virtual core::Property<Volume>& volume() = 0; |
357 | |
358 | virtual const core::Property<std::tuple<Track::UriType, Track::MetaData>>& track_meta_data() const = 0; |
359 | + |
360 | + virtual const core::Signal<void>& about_to_finish_signal() const = 0; |
361 | + virtual const core::Signal<uint64_t>& seeked_to_signal() const = 0; |
362 | + virtual const core::Signal<void>& end_of_stream_signal() const = 0; |
363 | }; |
364 | } |
365 | } |
366 | |
367 | === modified file 'src/core/media/gstreamer/engine.cpp' |
368 | --- src/core/media/gstreamer/engine.cpp 2014-02-20 19:05:17 +0000 |
369 | +++ src/core/media/gstreamer/engine.cpp 2014-04-17 21:13:23 +0000 |
370 | @@ -16,6 +16,9 @@ |
371 | * Authored by: Thomas Voß <thomas.voss@canonical.com> |
372 | */ |
373 | |
374 | +#include <stdio.h> |
375 | +#include <stdlib.h> |
376 | + |
377 | #include "bus.h" |
378 | #include "engine.h" |
379 | #include "meta_data_extractor.h" |
380 | @@ -43,14 +46,10 @@ |
381 | |
382 | struct gstreamer::Engine::Private |
383 | { |
384 | - void about_to_finish() |
385 | - { |
386 | - state = Engine::State::ready; |
387 | - } |
388 | - |
389 | void on_playbin_state_changed( |
390 | - const gstreamer::Bus::Message::Detail::StateChanged&) |
391 | + const gstreamer::Bus::Message::Detail::StateChanged& state_change) |
392 | { |
393 | + (void) state_change; |
394 | } |
395 | |
396 | void on_tag_available(const gstreamer::Bus::Message::Detail::Tag& tag) |
397 | @@ -163,13 +162,31 @@ |
398 | playbin.set_volume(new_volume.value); |
399 | } |
400 | |
401 | + void on_about_to_finish() |
402 | + { |
403 | + state = Engine::State::ready; |
404 | + about_to_finish(); |
405 | + } |
406 | + |
407 | + void on_seeked_to(uint64_t value) |
408 | + { |
409 | + seeked_to(value); |
410 | + } |
411 | + |
412 | + void on_end_of_stream() |
413 | + { |
414 | + end_of_stream(); |
415 | + } |
416 | + |
417 | Private() |
418 | : meta_data_extractor(new gstreamer::MetaDataExtractor()), |
419 | volume(media::Engine::Volume(1.)), |
420 | + is_video_source(false), |
421 | + is_audio_source(false), |
422 | about_to_finish_connection( |
423 | playbin.signals.about_to_finish.connect( |
424 | std::bind( |
425 | - &Private::about_to_finish, |
426 | + &Private::on_about_to_finish, |
427 | this))), |
428 | on_state_changed_connection( |
429 | playbin.signals.on_state_changed.connect( |
430 | @@ -188,7 +205,18 @@ |
431 | std::bind( |
432 | &Private::on_volume_changed, |
433 | this, |
434 | - std::placeholders::_1))) |
435 | + std::placeholders::_1))), |
436 | + on_seeked_to_connection( |
437 | + playbin.signals.on_seeked_to.connect( |
438 | + std::bind( |
439 | + &Private::on_seeked_to, |
440 | + this, |
441 | + std::placeholders::_1))), |
442 | + on_end_of_stream_connection( |
443 | + playbin.signals.on_end_of_stream.connect( |
444 | + std::bind( |
445 | + &Private::on_end_of_stream, |
446 | + this))) |
447 | { |
448 | } |
449 | |
450 | @@ -198,11 +226,19 @@ |
451 | core::Property<uint64_t> position; |
452 | core::Property<uint64_t> duration; |
453 | core::Property<media::Engine::Volume> volume; |
454 | + core::Property<bool> is_video_source; |
455 | + core::Property<bool> is_audio_source; |
456 | gstreamer::Playbin playbin; |
457 | core::ScopedConnection about_to_finish_connection; |
458 | core::ScopedConnection on_state_changed_connection; |
459 | core::ScopedConnection on_tag_available_connection; |
460 | core::ScopedConnection on_volume_changed_connection; |
461 | + core::ScopedConnection on_seeked_to_connection; |
462 | + core::ScopedConnection on_end_of_stream_connection; |
463 | + |
464 | + core::Signal<void> about_to_finish; |
465 | + core::Signal<uint64_t> seeked_to; |
466 | + core::Signal<void> end_of_stream; |
467 | }; |
468 | |
469 | gstreamer::Engine::Engine() : d(new Private{}) |
470 | @@ -231,6 +267,11 @@ |
471 | return true; |
472 | } |
473 | |
474 | +void gstreamer::Engine::create_video_sink(uint32_t texture_id) |
475 | +{ |
476 | + d->playbin.create_video_sink(texture_id); |
477 | +} |
478 | + |
479 | bool gstreamer::Engine::play() |
480 | { |
481 | auto result = d->playbin.set_state_and_wait(GST_STATE_PLAYING); |
482 | @@ -268,6 +309,28 @@ |
483 | return d->playbin.seek(ts); |
484 | } |
485 | |
486 | +const core::Property<bool>& gstreamer::Engine::is_video_source() const |
487 | +{ |
488 | + gstreamer::Playbin::MediaFileType type = d->playbin.media_file_type(); |
489 | + if (type == gstreamer::Playbin::MediaFileType::MEDIA_FILE_TYPE_VIDEO) |
490 | + d->is_video_source.set(true); |
491 | + else |
492 | + d->is_video_source.set(false); |
493 | + |
494 | + return d->is_video_source; |
495 | +} |
496 | + |
497 | +const core::Property<bool>& gstreamer::Engine::is_audio_source() const |
498 | +{ |
499 | + gstreamer::Playbin::MediaFileType type = d->playbin.media_file_type(); |
500 | + if (type == gstreamer::Playbin::MediaFileType::MEDIA_FILE_TYPE_AUDIO) |
501 | + d->is_audio_source.set(true); |
502 | + else |
503 | + d->is_audio_source.set(false); |
504 | + |
505 | + return d->is_audio_source; |
506 | +} |
507 | + |
508 | const core::Property<uint64_t>& gstreamer::Engine::position() const |
509 | { |
510 | d->position.set(d->playbin.position()); |
511 | @@ -295,3 +358,18 @@ |
512 | { |
513 | return d->track_meta_data; |
514 | } |
515 | + |
516 | +const core::Signal<void>& gstreamer::Engine::about_to_finish_signal() const |
517 | +{ |
518 | + return d->about_to_finish; |
519 | +} |
520 | + |
521 | +const core::Signal<uint64_t>& gstreamer::Engine::seeked_to_signal() const |
522 | +{ |
523 | + return d->seeked_to; |
524 | +} |
525 | + |
526 | +const core::Signal<void>& gstreamer::Engine::end_of_stream_signal() const |
527 | +{ |
528 | + return d->end_of_stream; |
529 | +} |
530 | |
531 | === modified file 'src/core/media/gstreamer/engine.h' |
532 | --- src/core/media/gstreamer/engine.h 2014-02-18 19:27:01 +0000 |
533 | +++ src/core/media/gstreamer/engine.h 2014-04-17 21:13:23 +0000 |
534 | @@ -33,12 +33,16 @@ |
535 | const core::Property<State>& state() const; |
536 | |
537 | bool open_resource_for_uri(const core::ubuntu::media::Track::UriType& uri); |
538 | + void create_video_sink(uint32_t texture_id); |
539 | |
540 | bool play(); |
541 | bool stop(); |
542 | bool pause(); |
543 | bool seek_to(const std::chrono::microseconds& ts); |
544 | |
545 | + const core::Property<bool>& is_video_source() const; |
546 | + const core::Property<bool>& is_audio_source() const; |
547 | + |
548 | const core::Property<uint64_t>& position() const; |
549 | const core::Property<uint64_t>& duration() const; |
550 | |
551 | @@ -47,6 +51,10 @@ |
552 | |
553 | const core::Property<std::tuple<core::ubuntu::media::Track::UriType, core::ubuntu::media::Track::MetaData>>& track_meta_data() const; |
554 | |
555 | + const core::Signal<void>& about_to_finish_signal() const; |
556 | + const core::Signal<uint64_t>& seeked_to_signal() const; |
557 | + const core::Signal<void>& end_of_stream_signal() const; |
558 | + |
559 | private: |
560 | struct Private; |
561 | std::unique_ptr<Private> d; |
562 | |
563 | === modified file 'src/core/media/gstreamer/playbin.h' |
564 | --- src/core/media/gstreamer/playbin.h 2014-02-20 19:05:17 +0000 |
565 | +++ src/core/media/gstreamer/playbin.h 2014-04-17 21:13:23 +0000 |
566 | @@ -21,6 +21,10 @@ |
567 | |
568 | #include "bus.h" |
569 | |
570 | +#include <hybris/media/media_codec_layer.h> |
571 | +#include <hybris/media/surface_texture_client_hybris.h> |
572 | + |
573 | +#include <gio/gio.h> |
574 | #include <gst/gst.h> |
575 | |
576 | #include <chrono> |
577 | @@ -37,6 +41,13 @@ |
578 | GST_PLAY_FLAG_TEXT = (1 << 2) |
579 | }; |
580 | |
581 | + enum MediaFileType |
582 | + { |
583 | + MEDIA_FILE_TYPE_NONE, |
584 | + MEDIA_FILE_TYPE_AUDIO, |
585 | + MEDIA_FILE_TYPE_VIDEO |
586 | + }; |
587 | + |
588 | static const std::string& pipeline_name() |
589 | { |
590 | static const std::string s{"playbin"}; |
591 | @@ -45,20 +56,22 @@ |
592 | |
593 | static void about_to_finish(GstElement*, |
594 | gpointer user_data) |
595 | - { auto thiz = static_cast<Playbin*>(user_data); |
596 | - |
597 | + { |
598 | + auto thiz = static_cast<Playbin*>(user_data); |
599 | thiz->signals.about_to_finish(); |
600 | } |
601 | |
602 | Playbin() |
603 | : pipeline(gst_element_factory_make("playbin", pipeline_name().c_str())), |
604 | bus{gst_element_get_bus(pipeline)}, |
605 | + file_type(MEDIA_FILE_TYPE_NONE), |
606 | on_new_message_connection( |
607 | bus.on_new_message.connect( |
608 | std::bind( |
609 | &Playbin::on_new_message, |
610 | this, |
611 | - std::placeholders::_1))) |
612 | + std::placeholders::_1))), |
613 | + is_seeking(false) |
614 | { |
615 | if (!pipeline) |
616 | throw std::runtime_error("Could not create pipeline for playbin."); |
617 | @@ -74,6 +87,8 @@ |
618 | this |
619 | ); |
620 | |
621 | + // When a client of media-hub dies, call on_client_died |
622 | + decoding_service_set_client_death_cb(&Playbin::on_client_died_cb, static_cast<void*>(this)); |
623 | } |
624 | |
625 | ~Playbin() |
626 | @@ -82,6 +97,43 @@ |
627 | gst_object_unref(pipeline); |
628 | } |
629 | |
630 | + static void on_client_died_cb(void *context) |
631 | + { |
632 | + if (context) |
633 | + { |
634 | + Playbin *pb = static_cast<Playbin*>(context); |
635 | + pb->on_client_died(); |
636 | + } |
637 | + } |
638 | + |
639 | + void on_client_died() |
640 | + { |
641 | + std::cout << "Client died, resetting pipeline" << std::endl; |
642 | + // When the client dies, tear down the current pipeline and get it |
643 | + // in a state that is ready for the next client that connects to the |
644 | + // service |
645 | + reset_pipeline(); |
646 | + } |
647 | + |
648 | + void reset_pipeline() |
649 | + { |
650 | + std::cout << __PRETTY_FUNCTION__ << std::endl; |
651 | + auto ret = gst_element_set_state(pipeline, GST_STATE_NULL); |
652 | + switch(ret) |
653 | + { |
654 | + case GST_STATE_CHANGE_FAILURE: |
655 | + std::cout << "Failed to reset the pipeline state. Client reconnect may not function properly." << std::endl; |
656 | + break; |
657 | + case GST_STATE_CHANGE_NO_PREROLL: |
658 | + case GST_STATE_CHANGE_SUCCESS: |
659 | + case GST_STATE_CHANGE_ASYNC: |
660 | + break; |
661 | + default: |
662 | + std::cout << "Failed to reset the pipeline state. Client reconnect may not function properly." << std::endl; |
663 | + } |
664 | + file_type = MEDIA_FILE_TYPE_NONE; |
665 | + } |
666 | + |
667 | void on_new_message(const Bus::Message& message) |
668 | { |
669 | switch(message.type) |
670 | @@ -101,6 +153,16 @@ |
671 | case GST_MESSAGE_STATE_CHANGED: |
672 | signals.on_state_changed(message.detail.state_changed); |
673 | break; |
674 | + case GST_MESSAGE_ASYNC_DONE: |
675 | + if (is_seeking) |
676 | + { |
677 | + // FIXME: Pass the actual playback time position to the signal call |
678 | + signals.on_seeked_to(0); |
679 | + is_seeking = false; |
680 | + } |
681 | + break; |
682 | + case GST_MESSAGE_EOS: |
683 | + signals.on_end_of_stream(); |
684 | default: |
685 | break; |
686 | } |
687 | @@ -126,6 +188,8 @@ |
688 | ::getenv("CORE_UBUNTU_MEDIA_SERVICE_AUDIO_SINK_NAME"), |
689 | "audio-sink"); |
690 | |
691 | + std::cout << "audio_sink: " << ::getenv("CORE_UBUNTU_MEDIA_SERVICE_AUDIO_SINK_NAME") << std::endl; |
692 | + |
693 | g_object_set ( |
694 | pipeline, |
695 | "audio-sink", |
696 | @@ -136,26 +200,41 @@ |
697 | if (::getenv("CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME") != nullptr) |
698 | { |
699 | auto video_sink = gst_element_factory_make ( |
700 | - ::getenv("CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME"), |
701 | - "video-sink"); |
702 | + ::getenv("CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME"), |
703 | + "video-sink"); |
704 | |
705 | std::cout << "video_sink: " << ::getenv("CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME") << std::endl; |
706 | |
707 | g_object_set ( |
708 | - pipeline, |
709 | - "video-sink", |
710 | - video_sink, |
711 | - NULL); |
712 | + pipeline, |
713 | + "video-sink", |
714 | + video_sink, |
715 | + NULL); |
716 | + } |
717 | + } |
718 | + |
719 | + void create_video_sink(uint32_t texture_id) |
720 | + { |
721 | + std::cout << "Creating video sink for texture_id: " << texture_id << std::endl; |
722 | + |
723 | + if (::getenv("CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME") != nullptr) |
724 | + { |
725 | + GstElement *video_sink = NULL; |
726 | + g_object_get (pipeline, "video_sink", &video_sink, NULL); |
727 | + |
728 | + // Get the service-side BufferQueue (IGraphicBufferProducer) and associate it with |
729 | + // the SurfaceTextureClientHybris instance |
730 | + IGBPWrapperHybris igbp = decoding_service_get_igraphicbufferproducer(); |
731 | + SurfaceTextureClientHybris stc = surface_texture_client_create_by_igbp(igbp); |
732 | + // Because mirsink is being loaded, we are definitely doing * hardware rendering. |
733 | + surface_texture_client_set_hardware_rendering (stc, TRUE); |
734 | + g_object_set (G_OBJECT (video_sink), "surface", static_cast<gpointer>(stc), static_cast<char*>(NULL)); |
735 | } |
736 | } |
737 | |
738 | void set_volume(double new_volume) |
739 | { |
740 | - g_object_set( |
741 | - pipeline, |
742 | - "volume", |
743 | - new_volume, |
744 | - NULL); |
745 | + g_object_set(pipeline, "volume", new_volume, NULL); |
746 | } |
747 | |
748 | uint64_t position() const |
749 | @@ -178,11 +257,11 @@ |
750 | |
751 | void set_uri(const std::string& uri) |
752 | { |
753 | - g_object_set( |
754 | - pipeline, |
755 | - "uri", |
756 | - uri.c_str(), |
757 | - NULL); |
758 | + g_object_set(pipeline, "uri", uri.c_str(), NULL); |
759 | + if (is_video_file(uri)) |
760 | + file_type = MEDIA_FILE_TYPE_VIDEO; |
761 | + else if (is_audio_file(uri)) |
762 | + file_type = MEDIA_FILE_TYPE_AUDIO; |
763 | } |
764 | |
765 | std::string uri() const |
766 | @@ -229,16 +308,96 @@ |
767 | |
768 | bool seek(const std::chrono::microseconds& ms) |
769 | { |
770 | + is_seeking = true; |
771 | return gst_element_seek_simple( |
772 | pipeline, |
773 | GST_FORMAT_TIME, |
774 | - (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT), |
775 | + (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT | |
776 | + GST_SEEK_FLAG_SNAP_BEFORE), |
777 | ms.count() * 1000); |
778 | } |
779 | |
780 | + std::string get_file_content_type(const std::string& uri) const |
781 | + { |
782 | + if (uri.empty()) |
783 | + return std::string(); |
784 | + |
785 | + std::string filename(uri); |
786 | + std::cout << "filename: " << filename << std::endl; |
787 | + size_t pos = uri.find("file://"); |
788 | + if (pos != std::string::npos) |
789 | + filename = uri.substr(pos + 7, std::string::npos); |
790 | + else |
791 | + // Anything other than a file, for now claim that the type |
792 | + // is both audio and video. |
793 | + // FIXME: implement true net stream sampling and get the type from GstCaps |
794 | + return std::string("audio/video/"); |
795 | + |
796 | + |
797 | + GError *error = nullptr; |
798 | + std::unique_ptr<GFile, void(*)(void *)> file( |
799 | + g_file_new_for_path(filename.c_str()), g_object_unref); |
800 | + std::unique_ptr<GFileInfo, void(*)(void *)> info( |
801 | + g_file_query_info( |
802 | + file.get(), G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE "," |
803 | + G_FILE_ATTRIBUTE_ETAG_VALUE, G_FILE_QUERY_INFO_NONE, |
804 | + /* cancellable */ NULL, &error), |
805 | + g_object_unref); |
806 | + if (!info) |
807 | + { |
808 | + std::string error_str(error->message); |
809 | + g_error_free(error); |
810 | + |
811 | + std::cout << "Failed to query the URI for the presence of video content: " |
812 | + << error_str << std::endl; |
813 | + return std::string(); |
814 | + } |
815 | + |
816 | + std::string content_type(g_file_info_get_attribute_string( |
817 | + info.get(), G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE)); |
818 | + |
819 | + return content_type; |
820 | + } |
821 | + |
822 | + bool is_audio_file(const std::string& uri) const |
823 | + { |
824 | + if (uri.empty()) |
825 | + return false; |
826 | + |
827 | + if (get_file_content_type(uri).find("audio/") == 0) |
828 | + { |
829 | + std::cout << "Found audio content" << std::endl; |
830 | + return true; |
831 | + } |
832 | + |
833 | + return false; |
834 | + } |
835 | + |
836 | + bool is_video_file(const std::string& uri) const |
837 | + { |
838 | + if (uri.empty()) |
839 | + return false; |
840 | + |
841 | + if (get_file_content_type(uri).find("video/") == 0) |
842 | + { |
843 | + std::cout << "Found video content" << std::endl; |
844 | + return true; |
845 | + } |
846 | + |
847 | + return false; |
848 | + } |
849 | + |
850 | + MediaFileType media_file_type() const |
851 | + { |
852 | + return file_type; |
853 | + } |
854 | + |
855 | GstElement* pipeline; |
856 | gstreamer::Bus bus; |
857 | + MediaFileType file_type; |
858 | + SurfaceTextureClientHybris stc_hybris; |
859 | core::Connection on_new_message_connection; |
860 | + bool is_seeking; |
861 | struct |
862 | { |
863 | core::Signal<void> about_to_finish; |
864 | @@ -247,6 +406,8 @@ |
865 | core::Signal<Bus::Message::Detail::ErrorWarningInfo> on_info; |
866 | core::Signal<Bus::Message::Detail::Tag> on_tag_available; |
867 | core::Signal<Bus::Message::Detail::StateChanged> on_state_changed; |
868 | + core::Signal<uint64_t> on_seeked_to; |
869 | + core::Signal<void> on_end_of_stream; |
870 | } signals; |
871 | }; |
872 | } |
873 | |
874 | === modified file 'src/core/media/mpris/player.h' |
875 | --- src/core/media/mpris/player.h 2014-02-18 19:27:01 +0000 |
876 | +++ src/core/media/mpris/player.h 2014-04-17 21:13:23 +0000 |
877 | @@ -54,11 +54,13 @@ |
878 | METHOD(Play, Player, std::chrono::seconds(1)) |
879 | METHOD(Seek, Player, std::chrono::seconds(1)) |
880 | METHOD(SetPosition, Player, std::chrono::seconds(1)) |
881 | + METHOD(CreateVideoSink, Player, std::chrono::seconds(1)) |
882 | METHOD(OpenUri, Player, std::chrono::seconds(1)) |
883 | |
884 | struct Signals |
885 | { |
886 | SIGNAL(Seeked, Player, uint64_t) |
887 | + SIGNAL(EndOfStream, Player, void) |
888 | }; |
889 | |
890 | struct Properties |
891 | @@ -74,6 +76,8 @@ |
892 | READABLE_PROPERTY(Duration, Player, uint64_t) |
893 | READABLE_PROPERTY(MinimumRate, Player, double) |
894 | READABLE_PROPERTY(MaximumRate, Player, double) |
895 | + READABLE_PROPERTY(IsVideoSource, Player, bool) |
896 | + READABLE_PROPERTY(IsAudioSource, Player, bool) |
897 | READABLE_PROPERTY(CanGoNext, Player, bool) |
898 | READABLE_PROPERTY(CanGoPrevious, Player, bool) |
899 | READABLE_PROPERTY(CanPlay, Player, bool) |
900 | |
901 | === modified file 'src/core/media/player_implementation.cpp' |
902 | --- src/core/media/player_implementation.cpp 2014-02-18 20:25:21 +0000 |
903 | +++ src/core/media/player_implementation.cpp 2014-04-17 21:13:23 +0000 |
904 | @@ -17,9 +17,13 @@ |
905 | |
906 | #include "player_implementation.h" |
907 | |
908 | +#include <unistd.h> |
909 | + |
910 | #include "engine.h" |
911 | #include "track_list_implementation.h" |
912 | |
913 | +#define UNUSED __attribute__((unused)) |
914 | + |
915 | namespace media = core::ubuntu::media; |
916 | |
917 | struct media::PlayerImplementation::Private |
918 | @@ -39,7 +43,7 @@ |
919 | { |
920 | engine->state().changed().connect( |
921 | [parent](const Engine::State& state) |
922 | - { |
923 | + { |
924 | switch(state) |
925 | { |
926 | case Engine::State::ready: parent->playback_status().set(media::Player::ready); break; |
927 | @@ -49,7 +53,8 @@ |
928 | default: |
929 | break; |
930 | }; |
931 | - }); |
932 | + }); |
933 | + |
934 | } |
935 | |
936 | PlayerImplementation* parent; |
937 | @@ -76,6 +81,8 @@ |
938 | can_seek().set(true); |
939 | can_go_previous().set(true); |
940 | can_go_next().set(true); |
941 | + is_video_source().set(false); |
942 | + is_audio_source().set(false); |
943 | is_shuffle().set(true); |
944 | playback_rate().set(1.f); |
945 | playback_status().set(Player::PlaybackStatus::null); |
946 | @@ -98,6 +105,38 @@ |
947 | return d->engine->duration().get(); |
948 | }; |
949 | duration().install(duration_getter); |
950 | + |
951 | + std::function<bool()> video_type_getter = [this]() |
952 | + { |
953 | + return d->engine->is_video_source().get(); |
954 | + }; |
955 | + is_video_source().install(video_type_getter); |
956 | + |
957 | + std::function<bool()> audio_type_getter = [this]() |
958 | + { |
959 | + return d->engine->is_audio_source().get(); |
960 | + }; |
961 | + is_audio_source().install(audio_type_getter); |
962 | + |
963 | + engine->about_to_finish_signal().connect([this]() |
964 | + { |
965 | + if (d->track_list->has_next()) |
966 | + { |
967 | + Track::UriType uri = d->track_list->query_uri_for_track(d->track_list->next()); |
968 | + if (!uri.empty()) |
969 | + d->parent->open_uri(uri); |
970 | + } |
971 | + }); |
972 | + |
973 | + engine->seeked_to_signal().connect([this](uint64_t value) |
974 | + { |
975 | + seeked_to()(value); |
976 | + }); |
977 | + |
978 | + engine->end_of_stream_signal().connect([this]() |
979 | + { |
980 | + end_of_stream()(); |
981 | + }); |
982 | } |
983 | |
984 | media::PlayerImplementation::~PlayerImplementation() |
985 | @@ -114,6 +153,17 @@ |
986 | return d->engine->open_resource_for_uri(uri); |
987 | } |
988 | |
989 | +void media::PlayerImplementation::create_video_sink(uint32_t texture_id) |
990 | +{ |
991 | + d->engine->create_video_sink(texture_id); |
992 | +} |
993 | + |
994 | +media::Player::GLConsumerWrapperHybris media::PlayerImplementation::gl_consumer() const |
995 | +{ |
996 | + // This method is client-side only and is simply a no-op for the service side |
997 | + return NULL; |
998 | +} |
999 | + |
1000 | void media::PlayerImplementation::next() |
1001 | { |
1002 | } |
1003 | @@ -124,11 +174,6 @@ |
1004 | |
1005 | void media::PlayerImplementation::play() |
1006 | { |
1007 | - /*if (playback_status() == media::Player::null) |
1008 | - { |
1009 | - if (d->track_list->has_next()) |
1010 | - if (open_uri(d->track_list->next()->)) |
1011 | - }*/ |
1012 | d->engine->play(); |
1013 | } |
1014 | |
1015 | @@ -142,6 +187,18 @@ |
1016 | d->engine->stop(); |
1017 | } |
1018 | |
1019 | +void media::PlayerImplementation::set_frame_available_callback( |
1020 | + UNUSED FrameAvailableCb cb, UNUSED void *context) |
1021 | +{ |
1022 | + // This method is client-side only and is simply a no-op for the service side |
1023 | +} |
1024 | + |
1025 | +void media::PlayerImplementation::set_playback_complete_callback( |
1026 | + UNUSED PlaybackCompleteCb cb, UNUSED void *context) |
1027 | +{ |
1028 | + // This method is client-side only and is simply a no-op for the service side |
1029 | +} |
1030 | + |
1031 | void media::PlayerImplementation::seek_to(const std::chrono::microseconds& ms) |
1032 | { |
1033 | d->engine->seek_to(ms); |
1034 | |
1035 | === modified file 'src/core/media/player_implementation.h' |
1036 | --- src/core/media/player_implementation.h 2014-02-18 20:25:21 +0000 |
1037 | +++ src/core/media/player_implementation.h 2014-04-17 21:13:23 +0000 |
1038 | @@ -43,11 +43,15 @@ |
1039 | virtual std::shared_ptr<TrackList> track_list(); |
1040 | |
1041 | virtual bool open_uri(const Track::UriType& uri); |
1042 | + virtual void create_video_sink(uint32_t texture_id); |
1043 | + virtual GLConsumerWrapperHybris gl_consumer() const; |
1044 | virtual void next(); |
1045 | virtual void previous(); |
1046 | virtual void play(); |
1047 | virtual void pause(); |
1048 | virtual void stop(); |
1049 | + virtual void set_frame_available_callback(FrameAvailableCb cb, void *context); |
1050 | + virtual void set_playback_complete_callback(PlaybackCompleteCb cb, void *context); |
1051 | virtual void seek_to(const std::chrono::microseconds& offset); |
1052 | |
1053 | private: |
1054 | |
1055 | === modified file 'src/core/media/player_skeleton.cpp' |
1056 | --- src/core/media/player_skeleton.cpp 2014-02-20 19:05:17 +0000 |
1057 | +++ src/core/media/player_skeleton.cpp 2014-04-17 21:13:23 +0000 |
1058 | @@ -16,6 +16,7 @@ |
1059 | * Authored by: Thomas Voß <thomas.voss@canonical.com> |
1060 | */ |
1061 | |
1062 | +#include "apparmor.h" |
1063 | #include "codec.h" |
1064 | #include "player_skeleton.h" |
1065 | #include "player_traits.h" |
1066 | @@ -27,6 +28,7 @@ |
1067 | #include <core/dbus/object.h> |
1068 | #include <core/dbus/property.h> |
1069 | #include <core/dbus/stub.h> |
1070 | +#include <core/dbus/asio/executor.h> |
1071 | |
1072 | namespace dbus = core::dbus; |
1073 | namespace media = core::ubuntu::media; |
1074 | @@ -36,6 +38,7 @@ |
1075 | Private(media::PlayerSkeleton* player, const dbus::types::ObjectPath& session) |
1076 | : impl(player), |
1077 | object(impl->access_service()->add_object_for_path(session)), |
1078 | + apparmor_session(nullptr), |
1079 | properties |
1080 | { |
1081 | object->get_property<mpris::Player::Properties::CanPlay>(), |
1082 | @@ -44,6 +47,8 @@ |
1083 | object->get_property<mpris::Player::Properties::CanControl>(), |
1084 | object->get_property<mpris::Player::Properties::CanGoNext>(), |
1085 | object->get_property<mpris::Player::Properties::CanGoPrevious>(), |
1086 | + object->get_property<mpris::Player::Properties::IsVideoSource>(), |
1087 | + object->get_property<mpris::Player::Properties::IsAudioSource>(), |
1088 | object->get_property<mpris::Player::Properties::PlaybackStatus>(), |
1089 | object->get_property<mpris::Player::Properties::LoopStatus>(), |
1090 | object->get_property<mpris::Player::Properties::PlaybackRate>(), |
1091 | @@ -54,6 +59,11 @@ |
1092 | object->get_property<mpris::Player::Properties::Duration>(), |
1093 | object->get_property<mpris::Player::Properties::MinimumRate>(), |
1094 | object->get_property<mpris::Player::Properties::MaximumRate>() |
1095 | + }, |
1096 | + signals |
1097 | + { |
1098 | + object->get_signal<mpris::Player::Signals::Seeked>(), |
1099 | + object->get_signal<mpris::Player::Signals::EndOfStream>() |
1100 | } |
1101 | { |
1102 | } |
1103 | @@ -111,18 +121,123 @@ |
1104 | { |
1105 | } |
1106 | |
1107 | + void handle_create_video_sink(const core::dbus::Message::Ptr& in) |
1108 | + { |
1109 | + uint32_t texture_id; |
1110 | + in->reader() >> texture_id; |
1111 | + impl->create_video_sink(texture_id); |
1112 | + |
1113 | + auto reply = dbus::Message::make_method_return(in); |
1114 | + impl->access_bus()->send(reply); |
1115 | + } |
1116 | + |
1117 | + std::string get_client_apparmor_context(const core::dbus::Message::Ptr& msg) |
1118 | + { |
1119 | + auto bus = std::shared_ptr<dbus::Bus>(new dbus::Bus(core::dbus::WellKnownBus::session)); |
1120 | + bus->install_executor(dbus::asio::make_executor(bus)); |
1121 | + |
1122 | + auto stub_service = dbus::Service::use_service(bus, dbus::traits::Service<core::Apparmor>::interface_name()); |
1123 | + apparmor_session = stub_service->object_for_path(dbus::types::ObjectPath("/org/freedesktop/DBus")); |
1124 | + // Get the AppArmor security context for the client |
1125 | + auto result = apparmor_session->invoke_method_synchronously<core::Apparmor::getConnectionAppArmorSecurityContext, std::string>(msg->sender()); |
1126 | + if (result.is_error()) |
1127 | + { |
1128 | + std::cout << "Error getting apparmor profile: " << result.error().print() << std::endl; |
1129 | + return std::string(); |
1130 | + } |
1131 | + |
1132 | + return result.value(); |
1133 | + } |
1134 | + |
1135 | + bool does_client_have_access(const std::string& context, const std::string& uri) |
1136 | + { |
1137 | + if (context.empty() || uri.empty()) |
1138 | + { |
1139 | + std::cout << "Client denied access since context or uri are empty" << std::endl; |
1140 | + return false; |
1141 | + } |
1142 | + |
1143 | + if (context == "unconfined") |
1144 | + { |
1145 | + std::cout << "Client allowed access since it's unconfined" << std::endl; |
1146 | + return true; |
1147 | + } |
1148 | + |
1149 | + size_t pos = context.find_first_of('_'); |
1150 | + if (pos == std::string::npos) |
1151 | + { |
1152 | + std::cout << "Client denied access since it's an invalid apparmor security context" << std::endl; |
1153 | + return false; |
1154 | + } |
1155 | + |
1156 | + const std::string pkgname = context.substr(0, pos); |
1157 | + std::cout << "client pkgname: " << pkgname << std::endl; |
1158 | + std::cout << "uri: " << uri << std::endl; |
1159 | + |
1160 | + // All confined apps can access their own files |
1161 | + if (uri.find(std::string(".local/share/" + pkgname + "/")) != std::string::npos |
1162 | + || uri.find(std::string(".cache/" + pkgname + "/")) != std::string::npos) |
1163 | + { |
1164 | + std::cout << "Client can access content in ~/.local/share/" << pkgname << " or ~/.cache/" << pkgname << std::endl; |
1165 | + return true; |
1166 | + } |
1167 | + else if (uri.find(std::string("opt/click.ubuntu.com/")) != std::string::npos |
1168 | + && uri.find(pkgname) != std::string::npos) |
1169 | + { |
1170 | + std::cout << "Client can access content in own opt directory" << std::endl; |
1171 | + return true; |
1172 | + } |
1173 | + else if ((uri.find(std::string("/system/media/audio/ui/")) != std::string::npos |
1174 | + || uri.find(std::string("/android/system/media/audio/ui/")) != std::string::npos) |
1175 | + && pkgname == "com.ubuntu.camera") |
1176 | + { |
1177 | + std::cout << "Camera app can access ui sounds" << std::endl; |
1178 | + return true; |
1179 | + } |
1180 | + // TODO: Check if the trust store previously allowed direct access to uri |
1181 | + |
1182 | + // Check in ~/Music and ~/Videos |
1183 | + // TODO: when the trust store lands, check it to see if this app can access the dirs and |
1184 | + // then remove the explicit whitelist of the music-app |
1185 | + else if (pkgname == "com.ubuntu.music" && |
1186 | + (uri.find(std::string("Music/")) != std::string::npos |
1187 | + || uri.find(std::string("Videos/")) != std::string::npos)) |
1188 | + { |
1189 | + std::cout << "Client can access content in ~/Music or ~/Videos" << std::endl; |
1190 | + return true; |
1191 | + } |
1192 | + else if (uri.find(std::string("http://")) != std::string::npos |
1193 | + || uri.find(std::string("rtsp://")) != std::string::npos) |
1194 | + { |
1195 | + std::cout << "Client can access streaming content" << std::endl; |
1196 | + return true; |
1197 | + } |
1198 | + else |
1199 | + { |
1200 | + std::cout << "Client denied access to open_uri()" << std::endl; |
1201 | + return false; |
1202 | + } |
1203 | + } |
1204 | + |
1205 | void handle_open_uri(const core::dbus::Message::Ptr& in) |
1206 | { |
1207 | Track::UriType uri; |
1208 | in->reader() >> uri; |
1209 | |
1210 | + std::string context = get_client_apparmor_context(in); |
1211 | + bool have_access = does_client_have_access(context, uri); |
1212 | + |
1213 | auto reply = dbus::Message::make_method_return(in); |
1214 | - reply->writer() << impl->open_uri(uri); |
1215 | + if (have_access) |
1216 | + reply->writer() << impl->open_uri(uri); |
1217 | + else |
1218 | + reply->writer() << false; |
1219 | impl->access_bus()->send(reply); |
1220 | } |
1221 | |
1222 | media::PlayerSkeleton* impl; |
1223 | dbus::Object::Ptr object; |
1224 | + dbus::Object::Ptr apparmor_session; |
1225 | struct |
1226 | { |
1227 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanPlay>> can_play; |
1228 | @@ -131,6 +246,8 @@ |
1229 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanControl>> can_control; |
1230 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanGoNext>> can_go_next; |
1231 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanGoPrevious>> can_go_previous; |
1232 | + std::shared_ptr<core::dbus::Property<mpris::Player::Properties::IsVideoSource>> is_video_source; |
1233 | + std::shared_ptr<core::dbus::Property<mpris::Player::Properties::IsAudioSource>> is_audio_source; |
1234 | |
1235 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::PlaybackStatus>> playback_status; |
1236 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::LoopStatus>> loop_status; |
1237 | @@ -144,10 +261,40 @@ |
1238 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MaximumRate>> maximum_playback_rate; |
1239 | } properties; |
1240 | |
1241 | - /*struct |
1242 | + struct Signals |
1243 | { |
1244 | - std::shared_ptr<dbus::Signal<mpris::Player::Signals::Seeked, uint64_t>> seeked; |
1245 | - } signals;*/ |
1246 | + typedef core::dbus::Signal<mpris::Player::Signals::Seeked, mpris::Player::Signals::Seeked::ArgumentType> DBusSeekedToSignal; |
1247 | + typedef core::dbus::Signal<mpris::Player::Signals::EndOfStream, mpris::Player::Signals::EndOfStream::ArgumentType> DBusEndOfStreamSignal; |
1248 | + |
1249 | + Signals(const std::shared_ptr<DBusSeekedToSignal>& seeked, |
1250 | + const std::shared_ptr<DBusEndOfStreamSignal>& eos) |
1251 | + : dbus |
1252 | + { |
1253 | + seeked, |
1254 | + eos |
1255 | + }, |
1256 | + seeked_to(), |
1257 | + end_of_stream() |
1258 | + { |
1259 | + seeked_to.connect([this](std::uint64_t value) |
1260 | + { |
1261 | + dbus.seeked_to->emit(value); |
1262 | + }); |
1263 | + |
1264 | + end_of_stream.connect([this]() |
1265 | + { |
1266 | + dbus.end_of_stream->emit(); |
1267 | + }); |
1268 | + } |
1269 | + |
1270 | + struct DBus |
1271 | + { |
1272 | + std::shared_ptr<DBusSeekedToSignal> seeked_to; |
1273 | + std::shared_ptr<DBusEndOfStreamSignal> end_of_stream; |
1274 | + } dbus; |
1275 | + core::Signal<uint64_t> seeked_to; |
1276 | + core::Signal<void> end_of_stream; |
1277 | + } signals; |
1278 | |
1279 | }; |
1280 | |
1281 | @@ -184,6 +331,10 @@ |
1282 | std::bind(&Private::handle_set_position, |
1283 | std::ref(d), |
1284 | std::placeholders::_1)); |
1285 | + d->object->install_method_handler<mpris::Player::CreateVideoSink>( |
1286 | + std::bind(&Private::handle_create_video_sink, |
1287 | + std::ref(d), |
1288 | + std::placeholders::_1)); |
1289 | d->object->install_method_handler<mpris::Player::OpenUri>( |
1290 | std::bind(&Private::handle_open_uri, |
1291 | std::ref(d), |
1292 | @@ -219,6 +370,16 @@ |
1293 | return *d->properties.can_go_next; |
1294 | } |
1295 | |
1296 | +const core::Property<bool>& media::PlayerSkeleton::is_video_source() const |
1297 | +{ |
1298 | + return *d->properties.is_video_source; |
1299 | +} |
1300 | + |
1301 | +const core::Property<bool>& media::PlayerSkeleton::is_audio_source() const |
1302 | +{ |
1303 | + return *d->properties.is_audio_source; |
1304 | +} |
1305 | + |
1306 | const core::Property<media::Player::PlaybackStatus>& media::PlayerSkeleton::playback_status() const |
1307 | { |
1308 | return *d->properties.playback_status; |
1309 | @@ -329,6 +490,17 @@ |
1310 | return *d->properties.can_go_next; |
1311 | } |
1312 | |
1313 | +core::Property<bool>& media::PlayerSkeleton::is_video_source() |
1314 | +{ |
1315 | + return *d->properties.is_video_source; |
1316 | +} |
1317 | + |
1318 | +core::Property<bool>& media::PlayerSkeleton::is_audio_source() |
1319 | +{ |
1320 | + return *d->properties.is_audio_source; |
1321 | +} |
1322 | + |
1323 | + |
1324 | core::Property<media::Track::MetaData>& media::PlayerSkeleton::meta_data_for_current_track() |
1325 | { |
1326 | return *d->properties.meta_data_for_current_track; |
1327 | @@ -346,6 +518,20 @@ |
1328 | |
1329 | const core::Signal<uint64_t>& media::PlayerSkeleton::seeked_to() const |
1330 | { |
1331 | - static const core::Signal<uint64_t> signal; |
1332 | - return signal; |
1333 | + return d->signals.seeked_to; |
1334 | +} |
1335 | + |
1336 | +core::Signal<uint64_t>& media::PlayerSkeleton::seeked_to() |
1337 | +{ |
1338 | + return d->signals.seeked_to; |
1339 | +} |
1340 | + |
1341 | +const core::Signal<void>& media::PlayerSkeleton::end_of_stream() const |
1342 | +{ |
1343 | + return d->signals.end_of_stream; |
1344 | +} |
1345 | + |
1346 | +core::Signal<void>& media::PlayerSkeleton::end_of_stream() |
1347 | +{ |
1348 | + return d->signals.end_of_stream; |
1349 | } |
1350 | |
1351 | === modified file 'src/core/media/player_skeleton.h' |
1352 | --- src/core/media/player_skeleton.h 2014-02-18 19:27:01 +0000 |
1353 | +++ src/core/media/player_skeleton.h 2014-04-17 21:13:23 +0000 |
1354 | @@ -1,4 +1,6 @@ |
1355 | /** |
1356 | + * Copyright (C) 2013-2014 Canonical Ltd |
1357 | + * |
1358 | * This program is free software: you can redistribute it and/or modify it |
1359 | * under the terms of the GNU Lesser General Public License version 3, |
1360 | * as published by the Free Software Foundation. |
1361 | @@ -46,6 +48,8 @@ |
1362 | virtual const core::Property<bool>& can_seek() const; |
1363 | virtual const core::Property<bool>& can_go_previous() const; |
1364 | virtual const core::Property<bool>& can_go_next() const; |
1365 | + virtual const core::Property<bool>& is_video_source() const; |
1366 | + virtual const core::Property<bool>& is_audio_source() const; |
1367 | virtual const core::Property<PlaybackStatus>& playback_status() const; |
1368 | virtual const core::Property<LoopStatus>& loop_status() const; |
1369 | virtual const core::Property<PlaybackRate>& playback_rate() const; |
1370 | @@ -63,6 +67,7 @@ |
1371 | virtual core::Property<Volume>& volume(); |
1372 | |
1373 | virtual const core::Signal<uint64_t>& seeked_to() const; |
1374 | + virtual const core::Signal<void>& end_of_stream() const; |
1375 | |
1376 | protected: |
1377 | PlayerSkeleton(const core::dbus::types::ObjectPath& session_path); |
1378 | @@ -73,12 +78,17 @@ |
1379 | virtual core::Property<bool>& can_seek(); |
1380 | virtual core::Property<bool>& can_go_previous(); |
1381 | virtual core::Property<bool>& can_go_next(); |
1382 | + virtual core::Property<bool>& is_video_source(); |
1383 | + virtual core::Property<bool>& is_audio_source(); |
1384 | virtual core::Property<Track::MetaData>& meta_data_for_current_track(); |
1385 | virtual core::Property<PlaybackRate>& minimum_playback_rate(); |
1386 | virtual core::Property<PlaybackRate>& maximum_playback_rate(); |
1387 | virtual core::Property<uint64_t>& position(); |
1388 | virtual core::Property<uint64_t>& duration(); |
1389 | |
1390 | + virtual core::Signal<uint64_t>& seeked_to(); |
1391 | + virtual core::Signal<void>& end_of_stream(); |
1392 | + |
1393 | private: |
1394 | struct Private; |
1395 | std::unique_ptr<Private> d; |
1396 | |
1397 | === modified file 'src/core/media/player_stub.cpp' |
1398 | --- src/core/media/player_stub.cpp 2014-02-20 19:05:17 +0000 |
1399 | +++ src/core/media/player_stub.cpp 2014-04-17 21:13:23 +0000 |
1400 | @@ -1,5 +1,5 @@ |
1401 | /* |
1402 | - * Copyright © 2013 Canonical Ltd. |
1403 | + * Copyright © 2013-2014 Canonical Ltd. |
1404 | * |
1405 | * This program is free software: you can redistribute it and/or modify it |
1406 | * under the terms of the GNU Lesser General Public License version 3, |
1407 | @@ -31,8 +31,14 @@ |
1408 | #include <core/dbus/property.h> |
1409 | #include <core/dbus/types/object_path.h> |
1410 | |
1411 | +// Hybris |
1412 | +#include <hybris/media/media_codec_layer.h> |
1413 | +#include <hybris/media/surface_texture_client_hybris.h> |
1414 | + |
1415 | #include <limits> |
1416 | |
1417 | +#define UNUSED __attribute__((unused)) |
1418 | + |
1419 | namespace dbus = core::dbus; |
1420 | namespace media = core::ubuntu::media; |
1421 | |
1422 | @@ -42,6 +48,12 @@ |
1423 | const std::shared_ptr<dbus::Service>& remote, |
1424 | const dbus::types::ObjectPath& path |
1425 | ) : parent(parent), |
1426 | + texture_id(0), |
1427 | + igbc_wrapper(nullptr), |
1428 | + glc_wrapper(nullptr), |
1429 | + decoding_session(decoding_service_create_session()), |
1430 | + frame_available_cb(nullptr), |
1431 | + frame_available_context(nullptr), |
1432 | path(path), |
1433 | object(remote->object_for_path(path)), |
1434 | properties |
1435 | @@ -52,6 +64,8 @@ |
1436 | object->get_property<mpris::Player::Properties::CanControl>(), |
1437 | object->get_property<mpris::Player::Properties::CanGoNext>(), |
1438 | object->get_property<mpris::Player::Properties::CanGoPrevious>(), |
1439 | + object->get_property<mpris::Player::Properties::IsVideoSource>(), |
1440 | + object->get_property<mpris::Player::Properties::IsAudioSource>(), |
1441 | object->get_property<mpris::Player::Properties::PlaybackStatus>(), |
1442 | object->get_property<mpris::Player::Properties::LoopStatus>(), |
1443 | object->get_property<mpris::Player::Properties::PlaybackRate>(), |
1444 | @@ -62,13 +76,67 @@ |
1445 | object->get_property<mpris::Player::Properties::Duration>(), |
1446 | object->get_property<mpris::Player::Properties::MinimumRate>(), |
1447 | object->get_property<mpris::Player::Properties::MaximumRate>() |
1448 | + }, |
1449 | + signals |
1450 | + { |
1451 | + object->get_signal<mpris::Player::Signals::Seeked>(), |
1452 | + object->get_signal<mpris::Player::Signals::EndOfStream>() |
1453 | } |
1454 | { |
1455 | } |
1456 | |
1457 | + ~Private() |
1458 | + { |
1459 | + } |
1460 | + |
1461 | + static void on_frame_available_cb(UNUSED GLConsumerWrapperHybris wrapper, void *context) |
1462 | + { |
1463 | + if (context != nullptr) { |
1464 | + Private *p = static_cast<Private*>(context); |
1465 | + p->on_frame_available(); |
1466 | + } |
1467 | + else |
1468 | + std::cout << "context is nullptr, can't call on_frame_available()" << std::endl; |
1469 | + } |
1470 | + |
1471 | + void on_frame_available() |
1472 | + { |
1473 | + if (frame_available_cb != nullptr) { |
1474 | + frame_available_cb(frame_available_context); |
1475 | + } |
1476 | + else |
1477 | + std::cout << "frame_available_cb is nullptr, can't call frame_available_cb()" << std::endl; |
1478 | + } |
1479 | + |
1480 | + void set_frame_available_cb(FrameAvailableCb cb, void *context) |
1481 | + { |
1482 | + frame_available_cb = cb; |
1483 | + frame_available_context = context; |
1484 | + |
1485 | + gl_consumer_set_frame_available_cb(glc_wrapper, &Private::on_frame_available_cb, static_cast<void*>(this)); |
1486 | + } |
1487 | + |
1488 | + /** We need a GLConsumerHybris instance for doing texture streaming over the |
1489 | + * process boundary **/ |
1490 | + void get_gl_consumer() |
1491 | + { |
1492 | + igbc_wrapper = decoding_service_get_igraphicbufferconsumer(); |
1493 | + glc_wrapper = gl_consumer_create_by_id_with_igbc(texture_id, igbc_wrapper); |
1494 | + |
1495 | + } |
1496 | + |
1497 | std::shared_ptr<Service> parent; |
1498 | std::shared_ptr<TrackList> track_list; |
1499 | |
1500 | + uint32_t texture_id; |
1501 | + IGBCWrapperHybris igbc_wrapper; |
1502 | + GLConsumerWrapperHybris glc_wrapper; |
1503 | + |
1504 | + DSSessionWrapperHybris decoding_session; |
1505 | + |
1506 | + FrameAvailableCb frame_available_cb; |
1507 | + void *frame_available_context; |
1508 | + |
1509 | dbus::Bus::Ptr bus; |
1510 | dbus::types::ObjectPath path; |
1511 | dbus::Object::Ptr object; |
1512 | @@ -81,6 +149,8 @@ |
1513 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanControl>> can_control; |
1514 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanGoNext>> can_go_next; |
1515 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanGoPrevious>> can_go_previous; |
1516 | + std::shared_ptr<core::dbus::Property<mpris::Player::Properties::IsVideoSource>> is_video_source; |
1517 | + std::shared_ptr<core::dbus::Property<mpris::Player::Properties::IsAudioSource>> is_audio_source; |
1518 | |
1519 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::PlaybackStatus>> playback_status; |
1520 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::LoopStatus>> loop_status; |
1521 | @@ -93,6 +163,56 @@ |
1522 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MinimumRate>> minimum_playback_rate; |
1523 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MaximumRate>> maximum_playback_rate; |
1524 | } properties; |
1525 | + |
1526 | + struct Signals |
1527 | + { |
1528 | + typedef core::dbus::Signal<mpris::Player::Signals::Seeked, mpris::Player::Signals::Seeked::ArgumentType> DBusSeekedToSignal; |
1529 | + typedef core::dbus::Signal<mpris::Player::Signals::EndOfStream, mpris::Player::Signals::EndOfStream::ArgumentType> DBusEndOfStreamSignal; |
1530 | + |
1531 | + Signals(const std::shared_ptr<DBusSeekedToSignal>& seeked, |
1532 | + const std::shared_ptr<DBusEndOfStreamSignal>& eos) |
1533 | + : dbus |
1534 | + { |
1535 | + seeked, |
1536 | + eos |
1537 | + }, |
1538 | + playback_complete_cb(nullptr), |
1539 | + playback_complete_context(nullptr), |
1540 | + seeked_to(), |
1541 | + end_of_stream() |
1542 | + { |
1543 | + dbus.seeked_to->connect([this](std::uint64_t value) |
1544 | + { |
1545 | + std::cout << "seeked_to signal arrived via the bus." << std::endl; |
1546 | + seeked_to(value); |
1547 | + }); |
1548 | + |
1549 | + dbus.end_of_stream->connect([this]() |
1550 | + { |
1551 | + std::cout << "EndOfStream signal arrived via the bus." << std::endl; |
1552 | + if (playback_complete_cb) |
1553 | + playback_complete_cb(playback_complete_context); |
1554 | + end_of_stream(); |
1555 | + }); |
1556 | + } |
1557 | + |
1558 | + struct DBus |
1559 | + { |
1560 | + std::shared_ptr<DBusSeekedToSignal> seeked_to; |
1561 | + std::shared_ptr<DBusEndOfStreamSignal> end_of_stream; |
1562 | + } dbus; |
1563 | + |
1564 | + void set_playback_complete_cb(PlaybackCompleteCb cb, void *context) |
1565 | + { |
1566 | + playback_complete_cb = cb; |
1567 | + playback_complete_context = context; |
1568 | + } |
1569 | + |
1570 | + PlaybackCompleteCb playback_complete_cb; |
1571 | + void *playback_complete_context; |
1572 | + core::Signal<uint64_t> seeked_to; |
1573 | + core::Signal<void> end_of_stream; |
1574 | + } signals; |
1575 | }; |
1576 | |
1577 | media::PlayerStub::PlayerStub( |
1578 | @@ -101,6 +221,11 @@ |
1579 | : dbus::Stub<Player>(the_session_bus()), |
1580 | d(new Private{parent, access_service(), object_path}) |
1581 | { |
1582 | + auto bus = the_session_bus(); |
1583 | + worker = std::move(std::thread([bus]() |
1584 | + { |
1585 | + bus->run(); |
1586 | + })); |
1587 | } |
1588 | |
1589 | media::PlayerStub::~PlayerStub() |
1590 | @@ -125,6 +250,21 @@ |
1591 | return op.value(); |
1592 | } |
1593 | |
1594 | +void media::PlayerStub::create_video_sink(uint32_t texture_id) |
1595 | +{ |
1596 | + auto op = d->object->invoke_method_synchronously<mpris::Player::CreateVideoSink, void>(texture_id); |
1597 | + d->texture_id = texture_id; |
1598 | + d->get_gl_consumer(); |
1599 | + |
1600 | + if (op.is_error()) |
1601 | + throw std::runtime_error("Problem creating new video sink instance on remote object"); |
1602 | +} |
1603 | + |
1604 | +GLConsumerWrapperHybris media::PlayerStub::gl_consumer() const |
1605 | +{ |
1606 | + return d->glc_wrapper; |
1607 | +} |
1608 | + |
1609 | void media::PlayerStub::next() |
1610 | { |
1611 | auto op = d->object->invoke_method_synchronously<mpris::Player::Next, void>(); |
1612 | @@ -173,6 +313,16 @@ |
1613 | throw std::runtime_error("Problem stopping playback on remote object"); |
1614 | } |
1615 | |
1616 | +void media::PlayerStub::set_frame_available_callback(FrameAvailableCb cb, void *context) |
1617 | +{ |
1618 | + d->set_frame_available_cb(cb, context); |
1619 | +} |
1620 | + |
1621 | +void media::PlayerStub::set_playback_complete_callback(PlaybackCompleteCb cb, void *context) |
1622 | +{ |
1623 | + d->signals.set_playback_complete_cb(cb, context); |
1624 | +} |
1625 | + |
1626 | const core::Property<bool>& media::PlayerStub::can_play() const |
1627 | { |
1628 | return *d->properties.can_play; |
1629 | @@ -198,6 +348,16 @@ |
1630 | return *d->properties.can_go_next; |
1631 | } |
1632 | |
1633 | +const core::Property<bool>& media::PlayerStub::is_video_source() const |
1634 | +{ |
1635 | + return *d->properties.is_video_source; |
1636 | +} |
1637 | + |
1638 | +const core::Property<bool>& media::PlayerStub::is_audio_source() const |
1639 | +{ |
1640 | + return *d->properties.is_audio_source; |
1641 | +} |
1642 | + |
1643 | const core::Property<media::Player::PlaybackStatus>& media::PlayerStub::playback_status() const |
1644 | { |
1645 | return *d->properties.playback_status; |
1646 | @@ -270,6 +430,10 @@ |
1647 | |
1648 | const core::Signal<uint64_t>& media::PlayerStub::seeked_to() const |
1649 | { |
1650 | - static core::Signal<uint64_t> signal; |
1651 | - return signal; |
1652 | + return d->signals.seeked_to; |
1653 | +} |
1654 | + |
1655 | +const core::Signal<void>& media::PlayerStub::end_of_stream() const |
1656 | +{ |
1657 | + return d->signals.end_of_stream; |
1658 | } |
1659 | |
1660 | === modified file 'src/core/media/player_stub.h' |
1661 | --- src/core/media/player_stub.h 2014-02-18 19:27:01 +0000 |
1662 | +++ src/core/media/player_stub.h 2014-04-17 21:13:23 +0000 |
1663 | @@ -45,6 +45,8 @@ |
1664 | virtual std::shared_ptr<TrackList> track_list(); |
1665 | |
1666 | virtual bool open_uri(const Track::UriType& uri); |
1667 | + virtual void create_video_sink(uint32_t texture_id); |
1668 | + virtual GLConsumerWrapperHybris gl_consumer() const; |
1669 | virtual void next(); |
1670 | virtual void previous(); |
1671 | virtual void play(); |
1672 | @@ -52,11 +54,16 @@ |
1673 | virtual void seek_to(const std::chrono::microseconds& offset); |
1674 | virtual void stop(); |
1675 | |
1676 | + virtual void set_frame_available_callback(FrameAvailableCb cb, void *context); |
1677 | + virtual void set_playback_complete_callback(PlaybackCompleteCb cb, void *context); |
1678 | + |
1679 | virtual const core::Property<bool>& can_play() const; |
1680 | virtual const core::Property<bool>& can_pause() const; |
1681 | virtual const core::Property<bool>& can_seek() const; |
1682 | virtual const core::Property<bool>& can_go_previous() const; |
1683 | virtual const core::Property<bool>& can_go_next() const; |
1684 | + virtual const core::Property<bool>& is_video_source() const; |
1685 | + virtual const core::Property<bool>& is_audio_source() const; |
1686 | virtual const core::Property<PlaybackStatus>& playback_status() const; |
1687 | virtual const core::Property<LoopStatus>& loop_status() const; |
1688 | virtual const core::Property<PlaybackRate>& playback_rate() const; |
1689 | @@ -74,10 +81,12 @@ |
1690 | virtual core::Property<Volume>& volume(); |
1691 | |
1692 | virtual const core::Signal<uint64_t>& seeked_to() const; |
1693 | + virtual const core::Signal<void>& end_of_stream() const; |
1694 | |
1695 | private: |
1696 | struct Private; |
1697 | std::unique_ptr<Private> d; |
1698 | + std::thread worker; |
1699 | }; |
1700 | } |
1701 | } |
1702 | |
1703 | === modified file 'src/core/media/server/server.cpp' |
1704 | --- src/core/media/server/server.cpp 2014-02-12 15:53:57 +0000 |
1705 | +++ src/core/media/server/server.cpp 2014-04-17 21:13:23 +0000 |
1706 | @@ -1,13 +1,41 @@ |
1707 | +/* |
1708 | + * Copyright (C) 2014 Canonical Ltd |
1709 | + * |
1710 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
1711 | + * you may not use this file except in compliance with the License. |
1712 | + * You may obtain a copy of the License at |
1713 | + * |
1714 | + * http://www.apache.org/licenses/LICENSE-2.0 |
1715 | + * |
1716 | + * Unless required by applicable law or agreed to in writing, software |
1717 | + * distributed under the License is distributed on an "AS IS" BASIS, |
1718 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
1719 | + * See the License for the specific language governing permissions and |
1720 | + * limitations under the License. |
1721 | + * |
1722 | + * Authored by: Jim Hodapp <jim.hodapp@canonical.com> |
1723 | + */ |
1724 | + |
1725 | #include <core/media/service.h> |
1726 | #include <core/media/player.h> |
1727 | #include <core/media/track_list.h> |
1728 | |
1729 | +#include <hybris/media/media_codec_layer.h> |
1730 | + |
1731 | #include "core/media/service_implementation.h" |
1732 | |
1733 | +#include <iostream> |
1734 | + |
1735 | namespace media = core::ubuntu::media; |
1736 | |
1737 | +using namespace std; |
1738 | + |
1739 | int main() |
1740 | { |
1741 | + // Init hybris-level DecodingService |
1742 | + decoding_service_init(); |
1743 | + cout << "Starting DecodingService..." << endl; |
1744 | + |
1745 | auto service = std::make_shared<media::ServiceImplementation>(); |
1746 | service->run(); |
1747 | |
1748 | |
1749 | === modified file 'src/core/media/service.cpp' |
1750 | --- src/core/media/service.cpp 2014-01-17 20:58:31 +0000 |
1751 | +++ src/core/media/service.cpp 2014-04-17 21:13:23 +0000 |
1752 | @@ -24,7 +24,7 @@ |
1753 | |
1754 | const std::shared_ptr<media::Service> media::Service::Client::instance() |
1755 | { |
1756 | - std::cout << "Creating a new Service instance" << std::endl; |
1757 | + std::cout << "Creating a new static Service instance" << std::endl; |
1758 | static std::shared_ptr<media::Service> instance{new media::ServiceStub()}; |
1759 | return instance; |
1760 | } |
1761 | |
1762 | === modified file 'src/core/media/track_list_implementation.cpp' |
1763 | --- src/core/media/track_list_implementation.cpp 2014-02-12 15:53:57 +0000 |
1764 | +++ src/core/media/track_list_implementation.cpp 2014-04-17 21:13:23 +0000 |
1765 | @@ -16,6 +16,9 @@ |
1766 | * Authored by: Thomas Voß <thomas.voss@canonical.com> |
1767 | */ |
1768 | |
1769 | +#include <stdio.h> |
1770 | +#include <stdlib.h> |
1771 | + |
1772 | #include "track_list_implementation.h" |
1773 | |
1774 | #include "engine.h" |
1775 | @@ -45,6 +48,16 @@ |
1776 | { |
1777 | } |
1778 | |
1779 | +media::Track::UriType media::TrackListImplementation::query_uri_for_track(const media::Track::Id& id) |
1780 | +{ |
1781 | + auto it = d->meta_data_cache.find(id); |
1782 | + |
1783 | + if (it == d->meta_data_cache.end()) |
1784 | + return Track::UriType{}; |
1785 | + |
1786 | + return std::get<0>(it->second); |
1787 | +} |
1788 | + |
1789 | media::Track::MetaData media::TrackListImplementation::query_meta_data_for_track(const media::Track::Id& id) |
1790 | { |
1791 | auto it = d->meta_data_cache.find(id); |
1792 | |
1793 | === modified file 'src/core/media/track_list_implementation.h' |
1794 | --- src/core/media/track_list_implementation.h 2014-02-12 15:53:57 +0000 |
1795 | +++ src/core/media/track_list_implementation.h 2014-04-17 21:13:23 +0000 |
1796 | @@ -36,6 +36,7 @@ |
1797 | const std::shared_ptr<Engine::MetaDataExtractor>& extractor); |
1798 | ~TrackListImplementation(); |
1799 | |
1800 | + Track::UriType query_uri_for_track(const Track::Id& id); |
1801 | Track::MetaData query_meta_data_for_track(const Track::Id& id); |
1802 | |
1803 | void add_track_with_uri_at(const Track::UriType& uri, const Track::Id& position, bool make_current); |
1804 | |
1805 | === modified file 'src/core/media/track_list_skeleton.cpp' |
1806 | --- src/core/media/track_list_skeleton.cpp 2014-02-12 15:53:57 +0000 |
1807 | +++ src/core/media/track_list_skeleton.cpp 2014-04-17 21:13:23 +0000 |
1808 | @@ -48,7 +48,8 @@ |
1809 | object(object), |
1810 | can_edit_tracks(object->get_property<mpris::TrackList::Properties::CanEditTracks>()), |
1811 | tracks(object->get_property<mpris::TrackList::Properties::Tracks>()), |
1812 | - current_track(tracks->get().begin()) |
1813 | + current_track(tracks->get().begin()), |
1814 | + empty_iterator(tracks->get().begin()) |
1815 | { |
1816 | } |
1817 | |
1818 | @@ -103,6 +104,7 @@ |
1819 | std::shared_ptr<core::dbus::Property<mpris::TrackList::Properties::CanEditTracks>> can_edit_tracks; |
1820 | std::shared_ptr<core::dbus::Property<mpris::TrackList::Properties::Tracks>> tracks; |
1821 | TrackList::ConstIterator current_track; |
1822 | + TrackList::ConstIterator empty_iterator; |
1823 | |
1824 | core::Signal<void> on_track_list_replaced; |
1825 | core::Signal<Track::Id> on_track_added; |
1826 | @@ -142,12 +144,22 @@ |
1827 | |
1828 | bool media::TrackListSkeleton::has_next() const |
1829 | { |
1830 | - return std::next(d->current_track) != d->tracks->get().end(); |
1831 | + return d->current_track != d->tracks->get().end(); |
1832 | } |
1833 | |
1834 | const media::Track::Id& media::TrackListSkeleton::next() |
1835 | { |
1836 | - return *(d->current_track = std::next(d->current_track)); |
1837 | + if (d->tracks->get().empty()) |
1838 | + return *(d->current_track); |
1839 | + |
1840 | + if (d->tracks->get().size() && (d->current_track == d->empty_iterator)) |
1841 | + { |
1842 | + d->current_track = d->tracks->get().begin(); |
1843 | + return *(d->current_track = std::next(d->current_track)); |
1844 | + } |
1845 | + |
1846 | + d->current_track = std::next(d->current_track); |
1847 | + return *(d->current_track); |
1848 | } |
1849 | |
1850 | const core::Property<bool>& media::TrackListSkeleton::can_edit_tracks() const |
1851 | |
1852 | === modified file 'src/core/media/track_list_skeleton.h' |
1853 | --- src/core/media/track_list_skeleton.h 2014-02-12 15:53:57 +0000 |
1854 | +++ src/core/media/track_list_skeleton.h 2014-04-17 21:13:23 +0000 |
1855 | @@ -48,9 +48,10 @@ |
1856 | const core::Signal<Track::Id>& on_track_removed() const; |
1857 | const core::Signal<Track::Id>& on_track_changed() const; |
1858 | |
1859 | + core::Property<Container>& tracks(); |
1860 | + |
1861 | protected: |
1862 | core::Property<bool>& can_edit_tracks(); |
1863 | - core::Property<Container>& tracks(); |
1864 | |
1865 | core::Signal<void>& on_track_list_replaced(); |
1866 | core::Signal<Track::Id>& on_track_added(); |
1867 | |
1868 | === modified file 'tests/acceptance-tests/service.cpp' |
1869 | --- tests/acceptance-tests/service.cpp 2014-03-06 19:23:19 +0000 |
1870 | +++ tests/acceptance-tests/service.cpp 2014-04-17 21:13:23 +0000 |
1871 | @@ -1,5 +1,5 @@ |
1872 | /* |
1873 | - * Copyright © 2013 Canonical Ltd. |
1874 | + * Copyright © 2013-2014 Canonical Ltd. |
1875 | * |
1876 | * This program is free software: you can redistribute it and/or modify it |
1877 | * under the terms of the GNU Lesser General Public License version 3, |
1878 | |
1879 | === modified file 'tests/unit-tests/CMakeLists.txt' |
1880 | --- tests/unit-tests/CMakeLists.txt 2014-01-17 20:58:31 +0000 |
1881 | +++ tests/unit-tests/CMakeLists.txt 2014-04-17 21:13:23 +0000 |
1882 | @@ -1,10 +1,21 @@ |
1883 | include_directories( |
1884 | . |
1885 | ${CMAKE_SOURCE_DIR}/src |
1886 | + ${PC_GSTREAMER_1_0_INCLUDE_DIRS} |
1887 | ) |
1888 | |
1889 | add_executable( |
1890 | test-gstreamer-engine |
1891 | + |
1892 | + libmedia-mock.cpp |
1893 | + ${CMAKE_SOURCE_DIR}/src/core/media/engine.cpp |
1894 | + ${CMAKE_SOURCE_DIR}/src/core/media/gstreamer/engine.cpp |
1895 | + ${CMAKE_SOURCE_DIR}/src/core/media/player_skeleton.cpp |
1896 | + ${CMAKE_SOURCE_DIR}/src/core/media/player_implementation.cpp |
1897 | + ${CMAKE_SOURCE_DIR}/src/core/media/service_skeleton.cpp |
1898 | + ${CMAKE_SOURCE_DIR}/src/core/media/service_implementation.cpp |
1899 | + ${CMAKE_SOURCE_DIR}/src/core/media/track_list_skeleton.cpp |
1900 | + ${CMAKE_SOURCE_DIR}/src/core/media/track_list_implementation.cpp |
1901 | test-gstreamer-engine.cpp |
1902 | ) |
1903 | |
1904 | @@ -13,12 +24,15 @@ |
1905 | |
1906 | media-hub-common |
1907 | media-hub-client |
1908 | - media-hub-service |
1909 | media-hub-test-framework |
1910 | |
1911 | ${CMAKE_THREAD_LIBS_INIT} |
1912 | ${Boost_LIBRARIES} |
1913 | ${DBUS_LIBRARIES} |
1914 | + ${DBUS_CPP_LDFLAGS} |
1915 | + ${GLog_LIBRARY} |
1916 | + ${PC_GSTREAMER_1_0_LIBRARIES} |
1917 | + ${GIO_LIBRARIES} |
1918 | |
1919 | gmock |
1920 | gmock_main |
1921 | |
1922 | === added file 'tests/unit-tests/libmedia-mock.cpp' |
1923 | --- tests/unit-tests/libmedia-mock.cpp 1970-01-01 00:00:00 +0000 |
1924 | +++ tests/unit-tests/libmedia-mock.cpp 2014-04-17 21:13:23 +0000 |
1925 | @@ -0,0 +1,26 @@ |
1926 | +/* |
1927 | + * Copyright © 2013-2014 Canonical Ltd. |
1928 | + * |
1929 | + * This program is free software: you can redistribute it and/or modify it |
1930 | + * under the terms of the GNU Lesser General Public License version 3, |
1931 | + * as published by the Free Software Foundation. |
1932 | + * |
1933 | + * This program is distributed in the hope that it will be useful, |
1934 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1935 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1936 | + * GNU Lesser General Public License for more details. |
1937 | + * |
1938 | + * You should have received a copy of the GNU Lesser General Public License |
1939 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1940 | + * |
1941 | + * Authored by: Jim Hodapp <jim.hodapp@canonical.com> |
1942 | + */ |
1943 | + |
1944 | +#include <hybris/media/media_codec_layer.h> |
1945 | +#include <hybris/media/surface_texture_client_hybris.h> |
1946 | + |
1947 | +#define UNUSED __attribute__((unused)) |
1948 | + |
1949 | +void decoding_service_set_client_death_cb(UNUSED DecodingClientDeathCbHybris callback, UNUSED void *context) |
1950 | +{ |
1951 | +} |
1952 | |
1953 | === modified file 'tests/unit-tests/test-gstreamer-engine.cpp' |
1954 | --- tests/unit-tests/test-gstreamer-engine.cpp 2014-02-26 14:58:36 +0000 |
1955 | +++ tests/unit-tests/test-gstreamer-engine.cpp 2014-04-17 21:13:23 +0000 |
1956 | @@ -1,5 +1,5 @@ |
1957 | /* |
1958 | - * Copyright © 2013 Canonical Ltd. |
1959 | + * Copyright © 2013-2014 Canonical Ltd. |
1960 | * |
1961 | * This program is free software: you can redistribute it and/or modify it |
1962 | * under the terms of the GNU Lesser General Public License version 3, |
1963 | @@ -198,7 +198,7 @@ |
1964 | std::chrono::seconds{40})); |
1965 | } |
1966 | |
1967 | -TEST(GStreamerEngine, DISABLED_stop_pause_play_seek_video_works) |
1968 | +TEST(GStreamerEngine, stop_pause_play_seek_video_works) |
1969 | { |
1970 | const std::string test_file{"/tmp/h264.avi"}; |
1971 | const std::string test_file_uri{"file:///tmp/h264.avi"}; |
1972 | @@ -248,8 +248,8 @@ |
1973 | |
1974 | TEST(GStreamerEngine, get_position_duration_work) |
1975 | { |
1976 | - const std::string test_file{"/tmp/test.ogg"}; |
1977 | - const std::string test_file_uri{"file:///tmp/test.ogg"}; |
1978 | + const std::string test_file{"/tmp/h264.avi"}; |
1979 | + const std::string test_file_uri{"file:///tmp/h264.avi"}; |
1980 | std::remove(test_file.c_str()); |
1981 | ASSERT_TRUE(test::copy_test_ogg_file_to(test_file)); |
1982 | |
1983 | @@ -269,10 +269,18 @@ |
1984 | EXPECT_TRUE(wst.wait_for_state_for( |
1985 | core::ubuntu::media::Engine::State::playing, |
1986 | std::chrono::milliseconds{4000})); |
1987 | - sleep(1); |
1988 | - |
1989 | - // FIXME: Ideally we want to seek_to and measure the position there, but seek_to seems |
1990 | - // broken from within this unit test |
1991 | + |
1992 | + EXPECT_TRUE(engine.seek_to(std::chrono::seconds{10})); |
1993 | + EXPECT_TRUE(engine.play()); |
1994 | + EXPECT_TRUE(wst.wait_for_state_for( |
1995 | + core::ubuntu::media::Engine::State::playing, |
1996 | + std::chrono::milliseconds{4000})); |
1997 | + |
1998 | + std::cout << "position: " << engine.position() << std::endl; |
1999 | + std::cout << "duration: " << engine.duration() << std::endl; |
2000 | + |
2001 | + // FIXME: This should be 10e9, but seek_to seems to be broken from within this unit test |
2002 | + // and I haven't been able to figure out why |
2003 | EXPECT_TRUE(engine.position() > 1e9); |
2004 | |
2005 | EXPECT_TRUE(engine.duration() > 1e9); |
FAILED: Continuous integration, rev:36 /code.launchpad .net/~jhodapp/ media-hub/ video-support/ +merge/ 212905/ +edit-commit- message
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https:/
http:// jenkins. qa.ubuntu. com/job/ media-hub- ci/30/ jenkins. qa.ubuntu. com/job/ media-hub- trusty- amd64-ci/ 31/console jenkins. qa.ubuntu. com/job/ media-hub- trusty- armhf-ci/ 30/console jenkins. qa.ubuntu. com/job/ media-hub- trusty- i386-ci/ 30/console
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/media- hub-ci/ 30/rebuild
http://