Merge lp:~phablet-team/media-hub/video-support into lp:media-hub

Proposed by Jim Hodapp
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
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

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:36
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://code.launchpad.net/~jhodapp/media-hub/video-support/+merge/212905/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/media-hub-ci/30/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/media-hub-trusty-amd64-ci/31/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/media-hub-trusty-armhf-ci/30/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/media-hub-trusty-i386-ci/30/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/media-hub-ci/30/rebuild

review: Needs Fixing (continuous-integration)
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
40. By Jim Hodapp

Get rid of the visibility attribute.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ricardo Mendoza (ricmm) wrote :

91 +include_directories(${PC_GSTREAMER_1_0_INCLUDE_DIRS} /usr/include/hybris)
99 + -lmedia

libmedia-dev ships a pkg config file for this

495 + std::cout << "IGBPWrapperHybris: " << igbp << std::endl;
496 + SurfaceTextureClientHybris stc = surface_texture_client_create_by_igbp(igbp);
497 + std::cout << "SurfaceTextureClientHybris: " << stc << std::endl;

Those couts are probably not needed anymore, even if we are keeping a good chunk of debug info

863 + seeked_to.connect([this](std::uint64_t value)
864 + {
865 + std::cout << "value: " << value << std::endl;
866 + //dbus.seeked_to->emit(value);
867 + });

Lets try and get rid of those ^

1166 + throw std::runtime_error("Problem switching to next track on remote object");

Odd error message from context

review: Needs Fixing
43. By Jim Hodapp

Made ricmm's change recommendations and enabled the tests that still work properly.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
44. By Jim Hodapp

Snap to the preceeding key unit after doing a seek.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
46. By Jim Hodapp

Enable the seeked_to signal

47. By Jim Hodapp

Merged with ricmm's EOS fix branch

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
50. By Jim Hodapp

Only start when dbus is started instead of preventing media-hub from being able to be stopped

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
51. By Jim Hodapp

Enable streaming sources to work with media-hub

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
52. By Jim Hodapp

Allow apps to access their own media files in /opt

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
53. By Jim Hodapp

Merged with jdstrand's changes to confine media-hub with apparmor

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
54. By Jim Hodapp

Slightly improve the get_position_duration_works unit test

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
55. By Jim Hodapp

Make sure the camer-app can play the click sound when a user captures a picture

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)

Preview Diff

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

Subscribers

People subscribed via source and target branches