Merge lp:~thomas-voss/media-hub/indicator-and-bluez-integration into lp:media-hub

Proposed by Thomas Voß
Status: Needs review
Proposed branch: lp:~thomas-voss/media-hub/indicator-and-bluez-integration
Merge into: lp:media-hub
Diff against target: 4022 lines (+2214/-787)
26 files modified
src/core/media/apparmor.h (+5/-12)
src/core/media/bluez/bluez.h (+350/-0)
src/core/media/gstreamer/engine.cpp (+3/-1)
src/core/media/mpris/media_player2.h (+177/-0)
src/core/media/mpris/mpris.h (+27/-0)
src/core/media/mpris/player.h (+236/-40)
src/core/media/player_implementation.cpp (+268/-118)
src/core/media/player_implementation.h (+32/-4)
src/core/media/player_p.h (+62/-0)
src/core/media/player_skeleton.cpp (+269/-366)
src/core/media/player_skeleton.h (+112/-7)
src/core/media/player_stub.cpp (+108/-97)
src/core/media/player_stub.h (+12/-6)
src/core/media/server/server.cpp (+9/-1)
src/core/media/service_implementation.cpp (+285/-7)
src/core/media/service_implementation.h (+23/-3)
src/core/media/service_skeleton.cpp (+5/-1)
src/core/media/service_stub.cpp (+51/-18)
src/core/media/service_stub.h (+5/-4)
src/core/media/track_list_implementation.cpp (+6/-9)
src/core/media/track_list_implementation.h (+10/-3)
src/core/media/track_list_skeleton.cpp (+17/-19)
src/core/media/track_list_skeleton.h (+11/-3)
src/core/media/track_list_stub.cpp (+32/-55)
src/core/media/track_list_stub.h (+32/-8)
tests/acceptance-tests/service.cpp (+67/-5)
To merge this branch: bzr merge lp:~thomas-voss/media-hub/indicator-and-bluez-integration
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing
Jim Hodapp Pending
Review via email: mp+225839@code.launchpad.net

Commit message

Wires up the per-player sessions to:

  * MPRIS, by owning an MPRIS-compliant name on the bus
  * Bluez, for enabling remote control of music-playback from bluetooth devices

Description of the change

Wires up the per-player sessions to:

  * MPRIS, by owning an MPRIS-compliant name on the bus
  * Bluez, for enabling remote control of music-playback from bluetooth devices

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

Unmerged revisions

63. By Thomas Voß

Factor out initialization of player properties.
Wire up property changes.

62. By Thomas Voß

Switch to immediate announcement policy for property updates on the MPRIS player skeleton.

61. By Thomas Voß

Add DesktopEntry property for mpris skeleton.
Make sure that org.mpris.MediaPlayer2 properties are initialized to sensible values.

60. By Thomas Voß

Switch to custom service names to expose mpris instances on the session bus.

59. By Thomas Voß

Restore original interface naming rules.

58. By Thomas Voß

Fix service name generation.

57. By Thomas Voß

Make mpris skeletons reusable.

56. By Thomas Voß

Add some debugging output.

55. By Thomas Voß

Announce track changes to bluez only when track actually changes.

54. By Thomas Voß

Query duration of tracks whenever meta-data changes.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/core/media/apparmor.h'
2--- src/core/media/apparmor.h 2014-04-22 17:23:43 +0000
3+++ src/core/media/apparmor.h 2014-07-07 14:32:42 +0000
4@@ -19,6 +19,8 @@
5 #ifndef APPARMOR_H_DBUS_
6 #define APPARMOR_H_DBUS_
7
8+#include <core/dbus/macros.h>
9+
10 #include <string>
11 #include <chrono>
12
13@@ -33,18 +35,9 @@
14 return s;
15 }
16
17- struct getConnectionAppArmorSecurityContext
18- {
19- static std::string name()
20- {
21- static std::string s = "GetConnectionAppArmorSecurityContext";
22- return s;
23- }
24-
25- static const std::chrono::milliseconds default_timeout() { return std::chrono::seconds{1}; }
26-
27- typedef Apparmor Interface;
28- };
29+ DBUS_CPP_METHOD_DEF(GetConnectionUnixUser, Apparmor)
30+ DBUS_CPP_METHOD_DEF(GetConnectionUnixProcessID, Apparmor)
31+ DBUS_CPP_METHOD_DEF(GetConnectionAppArmorSecurityContext, Apparmor)
32 };
33 }
34
35
36=== added directory 'src/core/media/bluez'
37=== added file 'src/core/media/bluez/bluez.h'
38--- src/core/media/bluez/bluez.h 1970-01-01 00:00:00 +0000
39+++ src/core/media/bluez/bluez.h 2014-07-07 14:32:42 +0000
40@@ -0,0 +1,350 @@
41+/*
42+ * Copyright © 2013 Canonical Ltd.
43+ *
44+ * This program is free software: you can redistribute it and/or modify it
45+ * under the terms of the GNU Lesser General Public License version 3,
46+ * as published by the Free Software Foundation.
47+ *
48+ * This program is distributed in the hope that it will be useful,
49+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
50+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
51+ * GNU Lesser General Public License for more details.
52+ *
53+ * You should have received a copy of the GNU Lesser General Public License
54+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
55+ *
56+ * Authored by: Thomas Voß <thomas.voss@canonical.com>
57+ */
58+
59+#ifndef ORG_BLUEZ_H_
60+#define ORG_BLUEZ_H_
61+
62+#include <core/dbus/macros.h>
63+#include <core/dbus/object.h>
64+#include <core/dbus/service.h>
65+#include <core/dbus/types/variant.h>
66+
67+#include <core/dbus/types/stl/map.h>
68+#include <core/dbus/types/stl/string.h>
69+
70+#include <functional>
71+#include <string>
72+
73+namespace org
74+{
75+struct Bluez
76+{
77+ static const std::string& name()
78+ {
79+ static const std::string s{"org.bluez"}; return s;
80+ }
81+
82+ struct Manager
83+ {
84+ static const std::string& name()
85+ {
86+ static const std::string s{"org.bluez.Manager"}; return s;
87+ }
88+
89+ // Returns object path for the default adapter.
90+ DBUS_CPP_METHOD_DEF(DefaultAdapter, Manager)
91+ };
92+
93+ struct Media
94+ {
95+ static const std::string& name()
96+ {
97+ static const std::string s{"org.bluez.Media"}; return s;
98+ }
99+
100+ struct Methods
101+ {
102+ // Register a media player object to sender, the sender
103+ // can register as many objets as it likes.
104+ // Note: If the sender disconnects its objects are
105+ // automatically unregistered.
106+ DBUS_CPP_METHOD_DEF(RegisterPlayer, Media)
107+ // Unregister sender media player.
108+ DBUS_CPP_METHOD_DEF(UnregisterPlayer, Media)
109+ };
110+ };
111+
112+ struct MediaPlayer
113+ {
114+ typedef std::tuple<std::string, core::dbus::types::Variant> DictionaryEntry;
115+ typedef std::map<std::string, core::dbus::types::Variant> Dictionary;
116+
117+ static const std::string& name()
118+ {
119+ static const std::string s{"org.bluez.MediaPlayer"}; return s;
120+ }
121+
122+ static core::dbus::types::ObjectPath create_unique_instance_path()
123+ {
124+ static std::uint32_t counter = 0;
125+ return core::dbus::types::ObjectPath
126+ {
127+ "/org/bluez/MediaPlayer/" + std::to_string(counter++)
128+ };
129+ }
130+
131+ struct Methods
132+ {
133+ DBUS_CPP_METHOD_DEF(SetProperty, MediaPlayer)
134+ DBUS_CPP_METHOD_DEF(Release, MediaPlayer)
135+ };
136+
137+ struct Signals
138+ {
139+ DBUS_CPP_SIGNAL_DEF(PropertyChanged, MediaPlayer, DictionaryEntry)
140+ DBUS_CPP_SIGNAL_DEF(TrackChanged, MediaPlayer, Dictionary)
141+ };
142+
143+ // The function call takes a dictionary of properties describing the
144+ // player object. We list all the properties including their names and value types here.
145+ struct Properties
146+ {
147+ // Just a "namespace", thus no creation.
148+ Properties() = delete;
149+
150+ // Whether an equalizer is in place for the player instance.
151+ struct Equalizer
152+ {
153+ static constexpr const char* name{"Equalizer"};
154+
155+ // The possible values.
156+ static constexpr const char* on{"on"};
157+ static constexpr const char* off{"off"};
158+
159+ typedef std::string ValueType;
160+ };
161+
162+ // The repeat mode of the player instance.
163+ struct Repeat
164+ {
165+ static constexpr const char* name{"Repeat"};
166+
167+ // The possible values.
168+ static constexpr const char* off{"off"};
169+ static constexpr const char* singletrack{"singletrack"};
170+ static constexpr const char* alltracks{"alltracks"};
171+ static constexpr const char* group{"group"};
172+
173+ typedef std::string ValueType;
174+ };
175+
176+ struct Scan
177+ {
178+ static constexpr const char* name{"Scan"};
179+
180+ // The possible values.
181+ static constexpr const char* off{"off"};
182+ static constexpr const char* alltracks{"alltracks"};
183+ static constexpr const char* group{"group"};
184+
185+ typedef std::string ValueType;
186+ };
187+
188+ struct Status
189+ {
190+ static constexpr const char* name{"Status"};
191+
192+ // The possible values.
193+ static constexpr const char* playing{"playing"};
194+ static constexpr const char* stopped{"stopped"};
195+ static constexpr const char* paused{"paused"};
196+ static constexpr const char* forward_seek{"forward-seek"};
197+ static constexpr const char* reverse_seek{"reverse-seek"};
198+ static constexpr const char* error{"error"};
199+
200+ typedef std::string ValueType;
201+ };
202+
203+ struct Position
204+ {
205+ static constexpr const char* name{"Position"};
206+ typedef std::uint32_t ValueType;
207+ };
208+
209+ struct Shuffle
210+ {
211+ static constexpr const char* name{"Shuffle"};
212+
213+ // The possible values.
214+ static constexpr const char* off{"off"};
215+ static constexpr const char* alltracks{"alltracks"};
216+ static constexpr const char* group{"group"};
217+
218+ typedef std::string ValueType;
219+ };
220+ };
221+
222+ // This is only here to summarize all the Track properties.
223+ struct Track
224+ {
225+ // Just a "namespace", thus no creation.
226+ Track() = delete;
227+
228+ // The function call takes a dictionary of meta-data describing the
229+ // current track/playlist. We list all the known meta-data here.
230+ struct MetaData
231+ {
232+ // Track title name
233+ struct Title
234+ {
235+ static constexpr const char* name{"Title"};
236+ typedef std::string ValueType;
237+ };
238+
239+ // Track artist name
240+ struct Artist
241+ {
242+ static constexpr const char* name{"Artist"};
243+ typedef std::string ValueType;
244+ };
245+
246+ // Track album name
247+ struct Album
248+ {
249+ static constexpr const char* name{"Album"};
250+ typedef std::string ValueType;
251+ };
252+
253+ // Track genre name
254+ struct Genre
255+ {
256+ static constexpr const char* name{"Genre"};
257+ typedef std::string ValueType;
258+ };
259+
260+ // Number of tracks in total
261+ struct NumberOfTracks
262+ {
263+ static constexpr const char* name{"NumberOfTracks"};
264+ typedef std::uint32_t ValueType;
265+ };
266+
267+ // Track number
268+ struct Number
269+ {
270+ static constexpr const char* name{"Number"};
271+ typedef std::uint32_t ValueType;
272+ };
273+
274+ // Track duration in milliseconds
275+ struct Duration
276+ {
277+ static constexpr const char* name{"Duration"};
278+ typedef std::uint32_t ValueType;
279+ };
280+ };
281+ };
282+
283+ struct Configuration
284+ {
285+ // Helper type for processing incoming dbus method invocations.
286+ // Implementations have to return the reply to the incoming message
287+ // provided as an argument to the handler.
288+ typedef std::function
289+ <
290+ core::dbus::Message::Ptr(const core::dbus::Message::Ptr&)
291+ > InvocationHandler;
292+
293+ // Returns a fallback invocation handler that just tells the other side: Not implemented.
294+ static const InvocationHandler& an_invocation_handler_returning_error()
295+ {
296+ static InvocationHandler invocation_handler = [](const core::dbus::Message::Ptr& msg)
297+ {
298+ return core::dbus::Message::make_error(msg, "not.implemented", "Message is not implemented");
299+ };
300+
301+ return invocation_handler;
302+ }
303+
304+ // The current dictionary of org.bluez.MediaPlayer properties.
305+ MediaPlayer::Dictionary media_player_properties;
306+ // The current dictionary of track metadata.
307+ MediaPlayer::Dictionary track_metadata;
308+ // The bus connection to use for dispatching replies.
309+ core::dbus::Bus::Ptr bus;
310+ // An existing stub object representing org.bluez.Media
311+ core::dbus::Object::Ptr bluez_media;
312+ // An existing service skeleton known on the bus.
313+ core::dbus::Service::Ptr service;
314+ // Method handler for invocations of SetProperty
315+ std::function<core::dbus::Message::Ptr(const core::dbus::Message::Ptr&)> on_set_property;
316+ // Method handler for invocations of Release.
317+ std::function<core::dbus::Message::Ptr(const core::dbus::Message::Ptr&)> on_release;
318+ };
319+
320+ MediaPlayer(const Configuration& configuration)
321+ : configuration(configuration),
322+ object(configuration.service->add_object_for_path(create_unique_instance_path())),
323+ sigs
324+ {
325+ object->get_signal<Signals::PropertyChanged>(),
326+ object->get_signal<Signals::TrackChanged>()
327+ }
328+ {
329+ object->install_method_handler<Methods::SetProperty>([this](const core::dbus::Message::Ptr& in)
330+ {
331+ auto reply = MediaPlayer::configuration.on_set_property(in);
332+ MediaPlayer::configuration.bus->send(reply);
333+ });
334+
335+ object->install_method_handler<Methods::Release>([this](const core::dbus::Message::Ptr& in)
336+ {
337+ auto reply = MediaPlayer::configuration.on_release(in);
338+ MediaPlayer::configuration.bus->send(reply);
339+ });
340+
341+ configuration.bluez_media->transact_method<org::Bluez::Media::Methods::RegisterPlayer, void>(
342+ // The path that this skeleton instance lives on.
343+ object->path(),
344+ // The properties of the underlying player instance.
345+ configuration.media_player_properties,
346+ // The current track metadata.
347+ configuration.track_metadata);
348+ }
349+
350+ ~MediaPlayer()
351+ {
352+ object->uninstall_method_handler<Methods::SetProperty>();
353+ object->uninstall_method_handler<Methods::Release>();
354+
355+ configuration.bluez_media->transact_method<org::Bluez::Media::Methods::UnregisterPlayer, void>(
356+ // The path that this skeleton instance lives on.
357+ object->path());
358+ }
359+
360+ template<typename Property>
361+ void set_property(const typename Property::ValueType& value)
362+ {
363+ sigs.property_changed->emit(
364+ std::make_tuple(
365+ std::string{Property::name},
366+ core::dbus::types::Variant::encode(value)));
367+ }
368+
369+ void set_track(const Dictionary& meta_data)
370+ {
371+ sigs.track_changed->emit(meta_data);
372+ }
373+
374+ // All creation-time configuration options
375+ Configuration configuration;
376+ // The actual object representing the player.
377+ core::dbus::Object::Ptr object;
378+ // All the signals defined on the object;
379+ struct
380+ {
381+ // Should be emitted whenever a property of the player instance changes.
382+ core::dbus::Signal<Signals::PropertyChanged, typename Signals::PropertyChanged::ArgumentType>::Ptr property_changed;
383+ // Should be emitted whenever the currently playing track changes.
384+ core::dbus::Signal<Signals::TrackChanged, typename Signals::TrackChanged::ArgumentType>::Ptr track_changed;
385+ } sigs;
386+ };
387+};
388+}
389+
390+#endif // ORG_BLUEZ_H_
391
392=== modified file 'src/core/media/gstreamer/engine.cpp'
393--- src/core/media/gstreamer/engine.cpp 2014-04-25 17:53:00 +0000
394+++ src/core/media/gstreamer/engine.cpp 2014-07-07 14:32:42 +0000
395@@ -56,7 +56,8 @@
396
397 void on_tag_available(const gstreamer::Bus::Message::Detail::Tag& tag)
398 {
399- media::Track::MetaData md;
400+ std::cout << __PRETTY_FUNCTION__ << std::endl;
401+ media::Track::MetaData md = std::get<1>(track_meta_data.get());
402
403 gst_tag_list_foreach(
404 tag.tag_list,
405@@ -64,6 +65,7 @@
406 const gchar* tag,
407 gpointer user_data)
408 {
409+ std::cout << "\t" << tag << std::endl;
410 (void) list;
411
412 static const std::map<std::string, std::string> gstreamer_to_mpris_tag_lut =
413
414=== added file 'src/core/media/mpris/media_player2.h'
415--- src/core/media/mpris/media_player2.h 1970-01-01 00:00:00 +0000
416+++ src/core/media/mpris/media_player2.h 2014-07-07 14:32:42 +0000
417@@ -0,0 +1,177 @@
418+/*
419+ * Copyright © 2013 Canonical Ltd.
420+ *
421+ * This program is free software: you can redistribute it and/or modify it
422+ * under the terms of the GNU Lesser General Public License version 3,
423+ * as published by the Free Software Foundation.
424+ *
425+ * This program is distributed in the hope that it will be useful,
426+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
427+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
428+ * GNU Lesser General Public License for more details.
429+ *
430+ * You should have received a copy of the GNU Lesser General Public License
431+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
432+ *
433+ * Authored by: Thomas Voß <thomas.voss@canonical.com>
434+ */
435+
436+#ifndef MPRIS_MEDIA_PLAYER2_H_
437+#define MPRIS_MEDIA_PLAYER2_H_
438+
439+#include <core/dbus/macros.h>
440+#include <core/dbus/object.h>
441+#include <core/dbus/property.h>
442+
443+#include <string>
444+#include <vector>
445+
446+namespace mpris
447+{
448+// Models interface org.mpris.MediaPlayer2, see:
449+// http://specifications.freedesktop.org/mpris-spec/latest/Media_Player.html
450+// for detailed documentation
451+struct MediaPlayer2
452+{
453+ static const std::string& name()
454+ {
455+ static const std::string s{"org.mpris.MediaPlayer2"}; return s;
456+ }
457+
458+ struct Methods
459+ {
460+ // Brings the media player's user interface to the front using any appropriate
461+ // mechanism available.
462+ // The media player may be unable to control how its user interface is displayed,
463+ // or it may not have a graphical user interface at all. In this case,
464+ // the CanRaise property is false and this method does nothing.
465+ DBUS_CPP_METHOD_DEF(Raise, MediaPlayer2)
466+
467+ // Causes the media player to stop running.
468+ // The media player may refuse to allow clients to shut it down. In this case, the
469+ // CanQuit property is false and this method does nothing.
470+ DBUS_CPP_METHOD_DEF(Quit, MediaPlayer2)
471+ };
472+
473+ struct Properties
474+ {
475+ // If false, calling Quit will have no effect, and may raise a NotSupported error.
476+ // If true, calling Quit will cause the media application to attempt to quit
477+ // (although it may still be prevented from quitting by the user, for example).
478+ DBUS_CPP_READABLE_PROPERTY_DEF(CanQuit, MediaPlayer2, bool)
479+
480+ // Whether the media player is occupying the fullscreen.
481+ // This property is optional. Clients should handle its absence gracefully.
482+ DBUS_CPP_WRITABLE_PROPERTY_DEF(Fullscreen, MediaPlayer2, bool)
483+
484+ // If false, attempting to set Fullscreen will have no effect, and may raise an error.
485+ // If true, attempting to set Fullscreen will not raise an error, and (if it is different
486+ // from the current value) will cause the media player to attempt to enter or exit fullscreen mode.
487+ // This property is optional. Clients should handle its absence gracefully.
488+ DBUS_CPP_READABLE_PROPERTY_DEF(CanSetFullscreen, MediaPlayer2, bool)
489+
490+ // If false, calling Raise will have no effect, and may raise a NotSupported error. If true, calling Raise
491+ // will cause the media application to attempt to bring its user interface to the front,
492+ // although it may be prevented from doing so (by the window manager, for example).
493+ DBUS_CPP_READABLE_PROPERTY_DEF(CanRaise, MediaPlayer2, bool)
494+
495+ // Indicates whether the /org/mpris/MediaPlayer2 object implements the
496+ // org.mpris.MediaPlayer2.TrackList interface.
497+ DBUS_CPP_READABLE_PROPERTY_DEF(HasTrackList, MediaPlayer2, bool)
498+
499+ // A friendly name to identify the media player to users.
500+ DBUS_CPP_READABLE_PROPERTY_DEF(Identity, MediaPlayer2, std::string)
501+
502+ // The basename of an installed .desktop file which complies with the Desktop entry specification,
503+ // with the ".desktop" extension stripped.
504+ // This property is optional. Clients should handle its absence gracefully.
505+ DBUS_CPP_READABLE_PROPERTY_DEF(DesktopEntry, MediaPlayer2, std::string)
506+
507+ // The URI schemes supported by the media player.
508+ DBUS_CPP_READABLE_PROPERTY_DEF(SupportedUriSchemes, MediaPlayer2, std::vector<std::string>)
509+
510+ // The mime-types supported by the media player.
511+ DBUS_CPP_READABLE_PROPERTY_DEF(SupportedMimeTypes, MediaPlayer2, std::vector<std::string>)
512+ };
513+
514+ struct Skeleton
515+ {
516+ // Creation time properties go here.
517+ struct Configuration
518+ {
519+ // Functor for handling incoming dbus calls
520+ typedef std::function<core::dbus::Message::Ptr(const core::dbus::Message::Ptr&)> InvocationHandler;
521+
522+ // Returns
523+ static InvocationHandler a_handler_returning_error()
524+ {
525+ return [](const core::dbus::Message::Ptr& in)
526+ {
527+ return core::dbus::Message::make_error(in, "org.freedesktop.DBus.Error.Failed", "Not implemented");
528+ };
529+ }
530+
531+ // The bus connection that should be used
532+ core::dbus::Bus::Ptr bus;
533+ // The dbus object that should implement org.mpris.MediaPlayer2
534+ core::dbus::Object::Ptr object;
535+ // Invocation handler for raise requests.
536+ InvocationHandler on_raise;
537+ // Invocation handler for quit requests.
538+ InvocationHandler on_quit;
539+ };
540+
541+ // Creates a new instance, sets up player properties and installs method handlers.
542+ Skeleton(const Configuration& configuration)
543+ : configuration(configuration),
544+ properties
545+ {
546+ configuration.object->get_property<Properties::CanQuit>(),
547+ configuration.object->get_property<Properties::Fullscreen>(),
548+ configuration.object->get_property<Properties::CanSetFullscreen>(),
549+ configuration.object->get_property<Properties::CanRaise>(),
550+ configuration.object->get_property<Properties::HasTrackList>(),
551+ configuration.object->get_property<Properties::Identity>(),
552+ configuration.object->get_property<Properties::DesktopEntry>(),
553+ configuration.object->get_property<Properties::SupportedUriSchemes>(),
554+ configuration.object->get_property<Properties::SupportedMimeTypes>()
555+ }
556+ {
557+ configuration.object->install_method_handler<Methods::Raise>([this](const core::dbus::Message::Ptr& msg)
558+ {
559+ Skeleton::configuration.bus->send(Skeleton::configuration.on_raise(msg));
560+ });
561+
562+ configuration.object->install_method_handler<Methods::Quit>([this](const core::dbus::Message::Ptr& msg)
563+ {
564+ Skeleton::configuration.bus->send(Skeleton::configuration.on_quit(msg));
565+ });
566+ }
567+
568+ ~Skeleton()
569+ {
570+ configuration.object->uninstall_method_handler<Methods::Quit>();
571+ configuration.object->uninstall_method_handler<Methods::Raise>();
572+ }
573+
574+ // We just store creation time properties here.
575+ Configuration configuration;
576+
577+ // All property instances go here.
578+ struct
579+ {
580+ std::shared_ptr<core::dbus::Property<Properties::CanQuit>> can_quit;
581+ std::shared_ptr<core::dbus::Property<Properties::Fullscreen>> fullscreen;
582+ std::shared_ptr<core::dbus::Property<Properties::CanSetFullscreen>> can_set_fullscreen;
583+ std::shared_ptr<core::dbus::Property<Properties::CanRaise>> can_raise;
584+ std::shared_ptr<core::dbus::Property<Properties::HasTrackList>> has_track_list;
585+ std::shared_ptr<core::dbus::Property<Properties::Identity>> identity;
586+ std::shared_ptr<core::dbus::Property<Properties::DesktopEntry>> desktop_entry;
587+ std::shared_ptr<core::dbus::Property<Properties::SupportedUriSchemes>> supported_uri_schemes;
588+ std::shared_ptr<core::dbus::Property<Properties::SupportedMimeTypes>> supported_mime_types;
589+ } properties;
590+ };
591+};
592+}
593+
594+#endif // MPRIS_MEDIA_PLAYER2_H_
595
596=== added file 'src/core/media/mpris/mpris.h'
597--- src/core/media/mpris/mpris.h 1970-01-01 00:00:00 +0000
598+++ src/core/media/mpris/mpris.h 2014-07-07 14:32:42 +0000
599@@ -0,0 +1,27 @@
600+/*
601+ * Copyright © 2013 Canonical Ltd.
602+ *
603+ * This program is free software: you can redistribute it and/or modify it
604+ * under the terms of the GNU Lesser General Public License version 3,
605+ * as published by the Free Software Foundation.
606+ *
607+ * This program is distributed in the hope that it will be useful,
608+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
609+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
610+ * GNU Lesser General Public License for more details.
611+ *
612+ * You should have received a copy of the GNU Lesser General Public License
613+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
614+ *
615+ * Authored by: Thomas Voß <thomas.voss@canonical.com>
616+ */
617+
618+#ifndef MPRIS_MPRIS_H_
619+#define MPRIS_MPRIS_H_
620+
621+namespace mpris
622+{
623+struct
624+}
625+
626+#define MPRIS_MPRIS_H_
627
628=== modified file 'src/core/media/mpris/player.h'
629--- src/core/media/mpris/player.h 2014-04-25 17:53:00 +0000
630+++ src/core/media/mpris/player.h 2014-07-07 14:32:42 +0000
631@@ -22,8 +22,12 @@
632 #include <core/media/player.h>
633 #include <core/media/track.h>
634
635-#include "macros.h"
636+#include "core/media/codec.h"
637
638+#include <core/dbus/bus.h>
639+#include <core/dbus/macros.h>
640+#include <core/dbus/object.h>
641+#include <core/dbus/property.h>
642 #include <core/dbus/types/any.h>
643 #include <core/dbus/types/object_path.h>
644 #include <core/dbus/types/variant.h>
645@@ -38,54 +42,246 @@
646
647 namespace mpris
648 {
649+template<typename Tag>
650 struct Player
651 {
652- static const std::string& name()
653- {
654- static const std::string s{"core.ubuntu.media.Service.Player"};
655- return s;
656- }
657-
658- METHOD(Next, Player, std::chrono::seconds(1))
659- METHOD(Previous, Player, std::chrono::seconds(1))
660- METHOD(Pause, Player, std::chrono::seconds(1))
661- METHOD(PlayPause, Player, std::chrono::seconds(1))
662- METHOD(Stop, Player, std::chrono::seconds(1))
663- METHOD(Play, Player, std::chrono::seconds(1))
664- METHOD(Seek, Player, std::chrono::seconds(1))
665- METHOD(SetPosition, Player, std::chrono::seconds(1))
666- METHOD(CreateVideoSink, Player, std::chrono::seconds(1))
667- METHOD(Key, Player, std::chrono::seconds(1))
668- METHOD(OpenUri, Player, std::chrono::seconds(1))
669+ struct LoopStatus
670+ {
671+ LoopStatus() = delete;
672+
673+ static constexpr const char* none{"None"};
674+ static constexpr const char* track{"Track"};
675+ static constexpr const char* playlist{"Playlist"};
676+ };
677+
678+ struct PlaybackStatus
679+ {
680+ PlaybackStatus() = delete;
681+
682+ static const char* from(core::ubuntu::media::Player::PlaybackStatus status)
683+ {
684+ switch(status)
685+ {
686+ case core::ubuntu::media::Player::PlaybackStatus::null:
687+ case core::ubuntu::media::Player::PlaybackStatus::ready:
688+ case core::ubuntu::media::Player::PlaybackStatus::stopped:
689+ return PlaybackStatus::stopped;
690+
691+ case core::ubuntu::media::Player::PlaybackStatus::playing:
692+ return PlaybackStatus::playing;
693+ case core::ubuntu::media::Player::PlaybackStatus::paused:
694+ return PlaybackStatus::paused;
695+ }
696+
697+ return nullptr;
698+ }
699+
700+ static constexpr const char* playing{"Playing"};
701+ static constexpr const char* paused{"Paused"};
702+ static constexpr const char* stopped{"Stopped"};
703+ };
704+
705+ typedef std::map<std::string, core::dbus::types::Variant> Dictionary;
706+
707+ DBUS_CPP_METHOD_DEF(Next, Player)
708+ DBUS_CPP_METHOD_DEF(Previous, Player)
709+ DBUS_CPP_METHOD_DEF(Pause, Player)
710+ DBUS_CPP_METHOD_DEF(PlayPause, Player)
711+ DBUS_CPP_METHOD_DEF(Stop, Player)
712+ DBUS_CPP_METHOD_DEF(Play, Player)
713+ DBUS_CPP_METHOD_DEF(Seek, Player)
714+ DBUS_CPP_METHOD_DEF(SetPosition, Player)
715+ DBUS_CPP_METHOD_DEF(CreateVideoSink, Player)
716+ DBUS_CPP_METHOD_DEF(Key, Player)
717+ DBUS_CPP_METHOD_DEF(OpenUri, Player)
718
719 struct Signals
720 {
721- SIGNAL(Seeked, Player, uint64_t)
722- SIGNAL(EndOfStream, Player, void)
723- SIGNAL(PlaybackStatusChanged, Player, core::ubuntu::media::Player::PlaybackStatus)
724+ DBUS_CPP_SIGNAL_DEF(Seeked, Player, std::uint64_t)
725+ DBUS_CPP_SIGNAL_DEF(EndOfStream, Player, void)
726+ DBUS_CPP_SIGNAL_DEF(PlaybackStatusChanged, Player, core::ubuntu::media::Player::PlaybackStatus)
727 };
728
729 struct Properties
730 {
731- READABLE_PROPERTY(PlaybackStatus, Player, core::ubuntu::media::Player::PlaybackStatus)
732- WRITABLE_PROPERTY(LoopStatus, Player, core::ubuntu::media::Player::LoopStatus)
733- WRITABLE_PROPERTY(PlaybackRate, Player, core::ubuntu::media::Player::PlaybackRate)
734- WRITABLE_PROPERTY(Rate, Player, double)
735- WRITABLE_PROPERTY(Shuffle, Player, bool)
736- READABLE_PROPERTY(MetaData, Player, core::ubuntu::media::Track::MetaData)
737- WRITABLE_PROPERTY(Volume, Player, double)
738- READABLE_PROPERTY(Position, Player, uint64_t)
739- READABLE_PROPERTY(Duration, Player, uint64_t)
740- READABLE_PROPERTY(MinimumRate, Player, double)
741- READABLE_PROPERTY(MaximumRate, Player, double)
742- READABLE_PROPERTY(IsVideoSource, Player, bool)
743- READABLE_PROPERTY(IsAudioSource, Player, bool)
744- READABLE_PROPERTY(CanGoNext, Player, bool)
745- READABLE_PROPERTY(CanGoPrevious, Player, bool)
746- READABLE_PROPERTY(CanPlay, Player, bool)
747- READABLE_PROPERTY(CanPause, Player, bool)
748- READABLE_PROPERTY(CanSeek, Player, bool)
749- READABLE_PROPERTY(CanControl, Player, bool)
750+ DBUS_CPP_READABLE_PROPERTY_DEF(PlaybackStatus, Player, std::string)
751+ DBUS_CPP_READABLE_PROPERTY_DEF(TypedPlaybackStatus, Player, core::ubuntu::media::Player::PlaybackStatus)
752+
753+ DBUS_CPP_WRITABLE_PROPERTY_DEF(LoopStatus, Player, std::string)
754+ DBUS_CPP_WRITABLE_PROPERTY_DEF(TypedLoopStatus, Player, core::ubuntu::media::Player::LoopStatus)
755+
756+ DBUS_CPP_WRITABLE_PROPERTY_DEF(PlaybackRate, Player, double)
757+ DBUS_CPP_WRITABLE_PROPERTY_DEF(Rate, Player, double)
758+ DBUS_CPP_WRITABLE_PROPERTY_DEF(Shuffle, Player, bool)
759+ DBUS_CPP_READABLE_PROPERTY_DEF(MetaData, Player, Dictionary)
760+ DBUS_CPP_READABLE_PROPERTY_DEF(TypedMetaData, Player, core::ubuntu::media::Track::MetaData)
761+ DBUS_CPP_WRITABLE_PROPERTY_DEF(Volume, Player, double)
762+ DBUS_CPP_READABLE_PROPERTY_DEF(Position, Player, std::uint64_t)
763+ DBUS_CPP_READABLE_PROPERTY_DEF(Duration, Player, std::uint64_t)
764+ DBUS_CPP_READABLE_PROPERTY_DEF(MinimumRate, Player, double)
765+ DBUS_CPP_READABLE_PROPERTY_DEF(MaximumRate, Player, double)
766+ DBUS_CPP_READABLE_PROPERTY_DEF(IsVideoSource, Player, bool)
767+ DBUS_CPP_READABLE_PROPERTY_DEF(IsAudioSource, Player, bool)
768+ DBUS_CPP_READABLE_PROPERTY_DEF(CanGoNext, Player, bool)
769+ DBUS_CPP_READABLE_PROPERTY_DEF(CanGoPrevious, Player, bool)
770+ DBUS_CPP_READABLE_PROPERTY_DEF(CanPlay, Player, bool)
771+ DBUS_CPP_READABLE_PROPERTY_DEF(CanPause, Player, bool)
772+ DBUS_CPP_READABLE_PROPERTY_DEF(CanSeek, Player, bool)
773+ DBUS_CPP_READABLE_PROPERTY_DEF(CanControl, Player, bool)
774+ };
775+
776+ // Convenience struct to create a skeleton implementation for org.mpris.MediaPlayer2.Player
777+ struct Skeleton
778+ {
779+ // Creation time options go here.
780+ struct Configuration
781+ {
782+ // Functor for handling incoming dbus calls
783+ typedef std::function<core::dbus::Message::Ptr(const core::dbus::Message::Ptr&)> InvocationHandler;
784+
785+ // The bus connection that should be used
786+ core::dbus::Bus::Ptr bus;
787+ // The dbus object that should implement org.mpris.MediaPlayer2
788+ core::dbus::Object::Ptr object;
789+ // Handles incoming calls for next. Never throws.
790+ InvocationHandler handle_next;
791+ // Handles incoming calls for previous. Never throws.
792+ InvocationHandler handle_previous;
793+ // Handles incoming calls for pause. Never throws.
794+ InvocationHandler handle_pause;
795+ // Handles incoming calls for stpo. Never throws.
796+ InvocationHandler handle_stop;
797+ // Handles incoming calls for play. Never throws.
798+ InvocationHandler handle_play;
799+ // Handles incoming calls for seek. Never throws.
800+ InvocationHandler handle_seek;
801+ // Handles incoming calls for video sink creation. Never throws.
802+ InvocationHandler handle_create_video_sink;
803+ // Handles incoming calls for key generation. Never throws.
804+ InvocationHandler handle_key;
805+ // Handles incoming calls for opening a URI. Never throws.
806+ InvocationHandler handle_open_uri;
807+ };
808+
809+ Skeleton(const Configuration& configuration)
810+ : configuration(configuration),
811+ properties
812+ {
813+ configuration.object->template get_property<typename mpris::Player<Tag>::Properties::CanPlay>(),
814+ configuration.object->template get_property<typename mpris::Player<Tag>::Properties::CanPause>(),
815+ configuration.object->template get_property<typename mpris::Player<Tag>::Properties::CanSeek>(),
816+ configuration.object->template get_property<typename mpris::Player<Tag>::Properties::CanControl>(),
817+ configuration.object->template get_property<typename mpris::Player<Tag>::Properties::CanGoNext>(),
818+ configuration.object->template get_property<typename mpris::Player<Tag>::Properties::CanGoPrevious>(),
819+ configuration.object->template get_property<typename mpris::Player<Tag>::Properties::IsVideoSource>(),
820+ configuration.object->template get_property<typename mpris::Player<Tag>::Properties::IsAudioSource>(),
821+ configuration.object->template get_property<typename mpris::Player<Tag>::Properties::PlaybackStatus>(),
822+ configuration.object->template get_property<typename mpris::Player<Tag>::Properties::TypedPlaybackStatus>(),
823+ configuration.object->template get_property<typename mpris::Player<Tag>::Properties::LoopStatus>(),
824+ configuration.object->template get_property<typename mpris::Player<Tag>::Properties::TypedLoopStatus>(),
825+ configuration.object->template get_property<typename mpris::Player<Tag>::Properties::PlaybackRate>(),
826+ configuration.object->template get_property<typename mpris::Player<Tag>::Properties::Shuffle>(),
827+ configuration.object->template get_property<typename mpris::Player<Tag>::Properties::TypedMetaData>(),
828+ configuration.object->template get_property<typename mpris::Player<Tag>::Properties::Volume>(),
829+ configuration.object->template get_property<typename mpris::Player<Tag>::Properties::Position>(),
830+ configuration.object->template get_property<typename mpris::Player<Tag>::Properties::Duration>(),
831+ configuration.object->template get_property<typename mpris::Player<Tag>::Properties::MinimumRate>(),
832+ configuration.object->template get_property<typename mpris::Player<Tag>::Properties::MaximumRate>()
833+ },
834+ signals
835+ {
836+ configuration.object->template get_signal<typename mpris::Player<Tag>::Signals::Seeked>(),
837+ configuration.object->template get_signal<typename mpris::Player<Tag>::Signals::EndOfStream>(),
838+ configuration.object->template get_signal<typename mpris::Player<Tag>::Signals::PlaybackStatusChanged>()
839+ }
840+ {
841+ Skeleton::configuration.object->template install_method_handler<typename mpris::Player<Tag>::Next>(
842+ [this](const core::dbus::Message::Ptr& in)
843+ {
844+ Skeleton::configuration.bus->send(Skeleton::configuration.handle_next(in));
845+ });
846+
847+ Skeleton::configuration.object->template install_method_handler<typename mpris::Player<Tag>::Previous>(
848+ [this](const core::dbus::Message::Ptr& in)
849+ {
850+ Skeleton::configuration.bus->send(Skeleton::configuration.handle_previous(in));
851+ });
852+ Skeleton::configuration.object->template install_method_handler<typename mpris::Player<Tag>::Pause>(
853+ [this](const core::dbus::Message::Ptr& in)
854+ {
855+ Skeleton::configuration.bus->send(Skeleton::configuration.handle_pause(in));
856+ });
857+ Skeleton::configuration.object->template install_method_handler<typename mpris::Player<Tag>::Stop>(
858+ [this](const core::dbus::Message::Ptr& in)
859+ {
860+ Skeleton::configuration.bus->send(Skeleton::configuration.handle_stop(in));
861+ });
862+ Skeleton::configuration.object->template install_method_handler<typename mpris::Player<Tag>::Play>(
863+ [this](const core::dbus::Message::Ptr& in)
864+ {
865+ Skeleton::configuration.bus->send(Skeleton::configuration.handle_play(in));
866+ });
867+ Skeleton::configuration.object->template install_method_handler<typename mpris::Player<Tag>::Seek>(
868+ [this](const core::dbus::Message::Ptr& in)
869+ {
870+ Skeleton::configuration.bus->send(Skeleton::configuration.handle_seek(in));
871+ });
872+ Skeleton::configuration.object->template install_method_handler<typename mpris::Player<Tag>::SetPosition>(
873+ [this](const core::dbus::Message::Ptr&)
874+ {
875+ // Skeleton::configuration.handle_set_position(in));
876+ });
877+ Skeleton::configuration.object->template install_method_handler<typename mpris::Player<Tag>::CreateVideoSink>(
878+ [this](const core::dbus::Message::Ptr& in)
879+ {
880+ Skeleton::configuration.bus->send(Skeleton::configuration.handle_create_video_sink(in));
881+ });
882+ Skeleton::configuration.object->template install_method_handler<typename mpris::Player<Tag>::Key>(
883+ [this](const core::dbus::Message::Ptr& in)
884+ {
885+ Skeleton::configuration.bus->send(Skeleton::configuration.handle_key(in));
886+ });
887+ Skeleton::configuration.object->template install_method_handler<typename mpris::Player<Tag>::OpenUri>(
888+ [this](const core::dbus::Message::Ptr& in)
889+ {
890+ Skeleton::configuration.bus->send(Skeleton::configuration.handle_open_uri(in));
891+ });
892+ }
893+
894+ // We just store creation time properties
895+ Configuration configuration;
896+ // All the properties exposed to the bus go here.
897+ struct
898+ {
899+ std::shared_ptr<core::dbus::Property<typename mpris::Player<Tag>::Properties::CanPlay>> can_play;
900+ std::shared_ptr<core::dbus::Property<typename mpris::Player<Tag>::Properties::CanPause>> can_pause;
901+ std::shared_ptr<core::dbus::Property<typename mpris::Player<Tag>::Properties::CanSeek>> can_seek;
902+ std::shared_ptr<core::dbus::Property<typename mpris::Player<Tag>::Properties::CanControl>> can_control;
903+ std::shared_ptr<core::dbus::Property<typename mpris::Player<Tag>::Properties::CanGoNext>> can_go_next;
904+ std::shared_ptr<core::dbus::Property<typename mpris::Player<Tag>::Properties::CanGoPrevious>> can_go_previous;
905+ std::shared_ptr<core::dbus::Property<typename mpris::Player<Tag>::Properties::IsVideoSource>> is_video_source;
906+ std::shared_ptr<core::dbus::Property<typename mpris::Player<Tag>::Properties::IsAudioSource>> is_audio_source;
907+
908+ std::shared_ptr<core::dbus::Property<typename mpris::Player<Tag>::Properties::PlaybackStatus>> playback_status;
909+ std::shared_ptr<core::dbus::Property<typename mpris::Player<Tag>::Properties::TypedPlaybackStatus>> typed_playback_status;
910+ std::shared_ptr<core::dbus::Property<typename mpris::Player<Tag>::Properties::LoopStatus>> loop_status;
911+ std::shared_ptr<core::dbus::Property<typename mpris::Player<Tag>::Properties::TypedLoopStatus>> typed_loop_status;
912+ std::shared_ptr<core::dbus::Property<typename mpris::Player<Tag>::Properties::PlaybackRate>> playback_rate;
913+ std::shared_ptr<core::dbus::Property<typename mpris::Player<Tag>::Properties::Shuffle>> is_shuffle;
914+ std::shared_ptr<core::dbus::Property<typename mpris::Player<Tag>::Properties::TypedMetaData>> meta_data_for_current_track;
915+ std::shared_ptr<core::dbus::Property<typename mpris::Player<Tag>::Properties::Volume>> volume;
916+ std::shared_ptr<core::dbus::Property<typename mpris::Player<Tag>::Properties::Position>> position;
917+ std::shared_ptr<core::dbus::Property<typename mpris::Player<Tag>::Properties::Duration>> duration;
918+ std::shared_ptr<core::dbus::Property<typename mpris::Player<Tag>::Properties::MinimumRate>> minimum_playback_rate;
919+ std::shared_ptr<core::dbus::Property<typename mpris::Player<Tag>::Properties::MaximumRate>> maximum_playback_rate;
920+ } properties;
921+
922+ struct
923+ {
924+ typename core::dbus::Signal<typename mpris::Player<Tag>::Signals::Seeked, typename mpris::Player<Tag>::Signals::Seeked::ArgumentType>::Ptr seeked_to;
925+ typename core::dbus::Signal<typename mpris::Player<Tag>::Signals::EndOfStream, typename mpris::Player<Tag>::Signals::EndOfStream::ArgumentType>::Ptr end_of_stream;
926+ typename core::dbus::Signal<typename mpris::Player<Tag>::Signals::PlaybackStatusChanged, typename mpris::Player<Tag>::Signals::PlaybackStatusChanged::ArgumentType>::Ptr playback_status_changed;
927+ } signals;
928 };
929 };
930 }
931
932=== modified file 'src/core/media/player_implementation.cpp'
933--- src/core/media/player_implementation.cpp 2014-06-24 17:03:27 +0000
934+++ src/core/media/player_implementation.cpp 2014-07-07 14:32:42 +0000
935@@ -19,12 +19,12 @@
936
937 #include <unistd.h>
938
939+#include "bluez/bluez.h"
940 #include "engine.h"
941 #include "track_list_implementation.h"
942
943 #include "powerd_service.h"
944 #include "unity_screen_service.h"
945-#include "gstreamer/engine.h"
946
947 #include <exception>
948 #include <iostream>
949@@ -38,65 +38,122 @@
950
951 struct media::PlayerImplementation::Private
952 {
953- Private(PlayerImplementation* parent,
954- const dbus::types::ObjectPath& session_path,
955- const std::shared_ptr<media::Service>& service,
956- PlayerImplementation::PlayerKey key)
957- : parent(parent),
958- service(service),
959- engine(std::make_shared<gstreamer::Engine>()),
960- session_path(session_path),
961- track_list(
962- new media::TrackListImplementation(
963- session_path.as_string() + "/TrackList",
964- engine->meta_data_extractor())),
965- sys_lock_name("media-hub-music-playback"),
966- active_display_on_request(false),
967- key(key)
968- {
969- auto bus = std::shared_ptr<dbus::Bus>(new dbus::Bus(core::dbus::WellKnownBus::system));
970- bus->install_executor(dbus::asio::make_executor(bus));
971-
972- auto stub_service = dbus::Service::use_service(bus, dbus::traits::Service<core::Powerd>::interface_name());
973- powerd_session = stub_service->object_for_path(dbus::types::ObjectPath("/com/canonical/powerd"));
974-
975- auto uscreen_stub_service = dbus::Service::use_service(bus, dbus::traits::Service<core::UScreen>::interface_name());
976- uscreen_session = uscreen_stub_service->object_for_path(dbus::types::ObjectPath("/com/canonical/Unity/Screen"));
977-
978- engine->state().changed().connect(
979- [parent, this](const Engine::State& state)
980- {
981- switch(state)
982- {
983- case Engine::State::ready:
984- {
985- parent->playback_status().set(media::Player::ready);
986- clear_power_state();
987- break;
988- }
989- case Engine::State::playing:
990- {
991- parent->playback_status().set(media::Player::playing);
992- request_power_state();
993- break;
994- }
995- case Engine::State::stopped:
996- {
997- parent->playback_status().set(media::Player::stopped);
998- clear_power_state();
999- break;
1000- }
1001- case Engine::State::paused:
1002- {
1003- parent->playback_status().set(media::Player::paused);
1004- clear_power_state();
1005- break;
1006- }
1007- default:
1008- break;
1009- };
1010- });
1011-
1012+ static org::Bluez::MediaPlayer::Dictionary engine_track_meta_data_to_bluez(const Track::MetaData& md)
1013+ {
1014+ org::Bluez::MediaPlayer::Dictionary dict;
1015+
1016+ if (md.count(media::Engine::Xesam::title()) > 0)
1017+ dict[org::Bluez::MediaPlayer::Track::MetaData::Title::name]
1018+ = core::dbus::types::Variant::encode
1019+ <
1020+ org::Bluez::MediaPlayer::Track::MetaData::Title::ValueType
1021+ >(md.get(media::Engine::Xesam::title()));
1022+
1023+ if (md.count(media::Engine::Xesam::artist()) > 0)
1024+ dict[org::Bluez::MediaPlayer::Track::MetaData::Artist::name]
1025+ = core::dbus::types::Variant::encode
1026+ <
1027+ org::Bluez::MediaPlayer::Track::MetaData::Artist::ValueType
1028+ >(md.get(media::Engine::Xesam::artist()));
1029+
1030+ if (md.count(media::Engine::Xesam::album()) > 0)
1031+ dict[org::Bluez::MediaPlayer::Track::MetaData::Album::name]
1032+ = core::dbus::types::Variant::encode
1033+ <
1034+ org::Bluez::MediaPlayer::Track::MetaData::Album::ValueType
1035+ >(md.get(media::Engine::Xesam::album()));
1036+
1037+ if (md.count(media::Engine::Xesam::genre()) > 0)
1038+ dict[org::Bluez::MediaPlayer::Track::MetaData::Genre::name]
1039+ = core::dbus::types::Variant::encode
1040+ <
1041+ org::Bluez::MediaPlayer::Track::MetaData::Genre::ValueType
1042+ >(md.get(media::Engine::Xesam::genre()));
1043+
1044+ if (md.count(media::Engine::Xesam::track_number()) > 0)
1045+ dict[org::Bluez::MediaPlayer::Track::MetaData::Number::name]
1046+ = core::dbus::types::Variant::encode
1047+ <
1048+ org::Bluez::MediaPlayer::Track::MetaData::Number::ValueType
1049+ >(std::stoi(md.get(media::Engine::Xesam::track_number())));
1050+
1051+ return dict;
1052+ }
1053+
1054+ Private(const media::PlayerImplementation::Configuration& config,
1055+ PlayerImplementation* parent)
1056+ : configuration(config),
1057+ parent(parent),
1058+ bluez_player
1059+ {
1060+ org::Bluez::MediaPlayer::Configuration
1061+ {
1062+ // We synchronize the initial player state with bluez
1063+ org::Bluez::MediaPlayer::Dictionary
1064+ {
1065+ // We do not support equalizers, yet
1066+ {
1067+ std::string{org::Bluez::MediaPlayer::Properties::Equalizer::name},
1068+ core::dbus::types::Variant::encode<std::string>
1069+ (
1070+ org::Bluez::MediaPlayer::Properties::Equalizer::off
1071+ )
1072+ },
1073+ // And our repeat mode is initially off
1074+ {
1075+ std::string{org::Bluez::MediaPlayer::Properties::Repeat::name},
1076+ core::dbus::types::Variant::encode<std::string>
1077+ (
1078+ org::Bluez::MediaPlayer::Properties::Repeat::off
1079+ )
1080+ },
1081+ // Scan mode is initially off
1082+ {
1083+ std::string{org::Bluez::MediaPlayer::Properties::Scan::name},
1084+ core::dbus::types::Variant::encode<std::string>(
1085+ std::string(org::Bluez::MediaPlayer::Properties::Scan::off))
1086+ },
1087+ // And we are in state stopped in the beginning
1088+ {
1089+ std::string{org::Bluez::MediaPlayer::Properties::Status::name},
1090+ core::dbus::types::Variant::encode<std::string>
1091+ (
1092+ org::Bluez::MediaPlayer::Properties::Status::stopped
1093+ )
1094+ },
1095+ // For that, we are at position 0
1096+ {
1097+ std::string{org::Bluez::MediaPlayer::Properties::Position::name},
1098+ core::dbus::types::Variant::encode<std::uint32_t>
1099+ (
1100+ 0
1101+ )
1102+ },
1103+ // And we do not shuffle
1104+ {
1105+ std::string{org::Bluez::MediaPlayer::Properties::Shuffle::name},
1106+ core::dbus::types::Variant::encode<std::string>
1107+ (
1108+ org::Bluez::MediaPlayer::Properties::Shuffle::off
1109+ )
1110+ }
1111+ },
1112+ // The current track is empty on construction, and with that the set of meta data.
1113+ org::Bluez::MediaPlayer::Dictionary{},
1114+ // The bus connection we want to expose the player skeleton upon.
1115+ configuration.system_bus,
1116+ // Stub for accessing org.bluez.Media
1117+ configuration.bluez_media,
1118+ // The already existing skeleton to piggy-back upon for exposing the player skeleton.
1119+ configuration.bluez,
1120+ // By default, we do not handle property updates.
1121+ org::Bluez::MediaPlayer::Configuration::an_invocation_handler_returning_error(),
1122+ // And we do not handle release messages.
1123+ org::Bluez::MediaPlayer::Configuration::an_invocation_handler_returning_error()
1124+ }
1125+ },
1126+ active_display_on_request(false)
1127+ {
1128 }
1129
1130 void request_power_state()
1131@@ -107,7 +164,11 @@
1132 {
1133 if (!active_display_on_request)
1134 {
1135- auto result = uscreen_session->invoke_method_synchronously<core::UScreen::keepDisplayOn, int>();
1136+ auto result = configuration.uscreen_session->invoke_method_synchronously
1137+ <
1138+ core::UScreen::keepDisplayOn,
1139+ int
1140+ >();
1141 if (result.is_error())
1142 throw std::runtime_error(result.error().print());
1143
1144@@ -119,7 +180,11 @@
1145 {
1146 if (sys_cookie.empty())
1147 {
1148- auto result = powerd_session->invoke_method_synchronously<core::Powerd::requestSysState, std::string>(sys_lock_name, static_cast<int>(1));
1149+ auto result = configuration.powerd_session->invoke_method_synchronously
1150+ <
1151+ core::Powerd::requestSysState,
1152+ std::string
1153+ >(std::string{PlayerImplementation::wake_lock_name}, static_cast<int>(1));
1154 if (result.is_error())
1155 throw std::runtime_error(result.error().print());
1156
1157@@ -142,7 +207,11 @@
1158 {
1159 if (active_display_on_request)
1160 {
1161- uscreen_session->invoke_method_synchronously<core::UScreen::removeDisplayOnRequest, void>(disp_cookie);
1162+ configuration.uscreen_session->invoke_method_synchronously
1163+ <
1164+ core::UScreen::removeDisplayOnRequest,
1165+ void
1166+ >(disp_cookie);
1167 active_display_on_request = false;
1168 }
1169 }
1170@@ -150,7 +219,11 @@
1171 {
1172 if (!sys_cookie.empty())
1173 {
1174- powerd_session->invoke_method_synchronously<core::Powerd::clearSysState, void>(sys_cookie);
1175+ configuration.powerd_session->invoke_method_synchronously
1176+ <
1177+ core::Powerd::clearSysState,
1178+ void
1179+ >(sys_cookie);
1180 sys_cookie.clear();
1181 }
1182 }
1183@@ -162,30 +235,130 @@
1184 }
1185 }
1186
1187+ void setup_connections_to_engine(const media::Engine& eng)
1188+ {
1189+ /* TODO(tvoss): Re-enable
1190+ eng.about_to_finish_signal().connect([this]()
1191+ {
1192+ if (configuration.track_list->has_next())
1193+ {
1194+ Track::UriType uri = configuration.track_list->query_uri_for_track(configuration.track_list->next());
1195+ if (!uri.empty())
1196+ parent->open_uri(uri);
1197+ }
1198+ });
1199+ */
1200+
1201+ eng.state().changed().connect(
1202+ [this](const Engine::State& state)
1203+ {
1204+ switch(state)
1205+ {
1206+ case Engine::State::ready:
1207+ {
1208+ parent->playback_status().set(media::Player::ready);
1209+ clear_power_state();
1210+ break;
1211+ }
1212+ case Engine::State::playing:
1213+ {
1214+ parent->playback_status().set(media::Player::playing);
1215+ request_power_state();
1216+ break;
1217+ }
1218+ case Engine::State::stopped:
1219+ {
1220+ parent->playback_status().set(media::Player::stopped);
1221+ clear_power_state();
1222+ break;
1223+ }
1224+ case Engine::State::paused:
1225+ {
1226+ parent->playback_status().set(media::Player::paused);
1227+ clear_power_state();
1228+ break;
1229+ }
1230+ default:
1231+ break;
1232+ };
1233+ });
1234+
1235+ eng.seeked_to_signal().connect([this](uint64_t value)
1236+ {
1237+ parent->seeked_to()(value);
1238+ // Update the bluez player.
1239+ bluez_player.set_property<org::Bluez::MediaPlayer::Properties::Position>(value);
1240+ });
1241+
1242+ eng.end_of_stream_signal().connect([this]()
1243+ {
1244+ parent->end_of_stream()();
1245+ });
1246+
1247+ eng.playback_status_changed_signal().connect([this](const Player::PlaybackStatus& status)
1248+ {
1249+ parent->playback_status_changed()(status);
1250+
1251+ // Update the bluez player.
1252+ switch(status)
1253+ {
1254+ case Player::PlaybackStatus::null:
1255+ case Player::PlaybackStatus::ready:
1256+ case Player::PlaybackStatus::stopped:
1257+ bluez_player.set_property<org::Bluez::MediaPlayer::Properties::Status>(
1258+ org::Bluez::MediaPlayer::Properties::Status::stopped);
1259+ break;
1260+ case Player::PlaybackStatus::playing:
1261+ {
1262+ // We update the current track data in one go.
1263+ auto dict = engine_track_meta_data_to_bluez(std::get<1>(configuration.engine->track_meta_data().get()));
1264+ // Duration of the track is not reported as meta data but has to be queried explicitly.
1265+ dict[org::Bluez::MediaPlayer::Track::MetaData::Duration::name]
1266+ = core::dbus::types::Variant::encode
1267+ <
1268+ org::Bluez::MediaPlayer::Track::MetaData::Duration::ValueType
1269+ >(configuration.engine->duration().get());
1270+ // Announce the track to bluez.
1271+ bluez_player.set_track(dict);
1272+ // And set state to playing.
1273+ bluez_player.set_property<org::Bluez::MediaPlayer::Properties::Status>(
1274+ org::Bluez::MediaPlayer::Properties::Status::playing);
1275+ break;
1276+ }
1277+ case Player::PlaybackStatus::paused:
1278+ bluez_player.set_property<org::Bluez::MediaPlayer::Properties::Status>(
1279+ org::Bluez::MediaPlayer::Properties::Status::paused);
1280+ break;
1281+ }
1282+ });
1283+
1284+ /*eng.track_meta_data().changed().connect([this](const std::tuple<Track::UriType, Track::MetaData>& tuple)
1285+ {
1286+ auto dict = engine_track_meta_data_to_bluez(std::get<1>(tuple));
1287+ dict[org::Bluez::MediaPlayer::Track::MetaData::Duration::name]
1288+ = core::dbus::types::Variant::encode
1289+ <
1290+ org::Bluez::MediaPlayer::Track::MetaData::Duration::ValueType
1291+ >(configuration.engine->duration().get());
1292+
1293+ // And finally update the bluez_player instance.
1294+ bluez_player.set_track(dict);
1295+ });*/
1296+ }
1297+
1298+ media::PlayerImplementation::Configuration configuration;
1299 PlayerImplementation* parent;
1300- std::shared_ptr<Service> service;
1301- std::shared_ptr<Engine> engine;
1302- dbus::types::ObjectPath session_path;
1303- std::shared_ptr<TrackListImplementation> track_list;
1304- std::shared_ptr<dbus::Object> powerd_session;
1305- std::shared_ptr<dbus::Object> uscreen_session;
1306- std::string sys_lock_name;
1307+ // All bluez-specific fields go here.
1308+ org::Bluez::MediaPlayer bluez_player;
1309+ // All powerd-specific fields go here.
1310 int disp_cookie;
1311 bool active_display_on_request;
1312 std::string sys_cookie;
1313- PlayerImplementation::PlayerKey key;
1314 };
1315
1316-media::PlayerImplementation::PlayerImplementation(
1317- const dbus::types::ObjectPath& session_path,
1318- const std::shared_ptr<Service>& service,
1319- PlayerKey key)
1320- : media::PlayerSkeleton(session_path),
1321- d(new Private(
1322- this,
1323- session_path,
1324- service,
1325- key))
1326+media::PlayerImplementation::PlayerImplementation(const media::PlayerImplementation::Configuration& config)
1327+ : media::PlayerSkeleton(config.skeleton_configuration),
1328+ d(new Private(config, this))
1329 {
1330 // Initializing default values for properties
1331 can_play().set(true);
1332@@ -206,7 +379,7 @@
1333 // every time the client requests position
1334 std::function<uint64_t()> position_getter = [this]()
1335 {
1336- return d->engine->position().get();
1337+ return d->configuration.engine->position().get();
1338 };
1339 position().install(position_getter);
1340
1341@@ -214,46 +387,23 @@
1342 // every time the client requests duration
1343 std::function<uint64_t()> duration_getter = [this]()
1344 {
1345- return d->engine->duration().get();
1346+ return d->configuration.engine->duration().get();
1347 };
1348 duration().install(duration_getter);
1349
1350 std::function<bool()> video_type_getter = [this]()
1351 {
1352- return d->engine->is_video_source().get();
1353+ return d->configuration.engine->is_video_source().get();
1354 };
1355 is_video_source().install(video_type_getter);
1356
1357 std::function<bool()> audio_type_getter = [this]()
1358 {
1359- return d->engine->is_audio_source().get();
1360+ return d->configuration.engine->is_audio_source().get();
1361 };
1362 is_audio_source().install(audio_type_getter);
1363
1364- d->engine->about_to_finish_signal().connect([this]()
1365- {
1366- if (d->track_list->has_next())
1367- {
1368- Track::UriType uri = d->track_list->query_uri_for_track(d->track_list->next());
1369- if (!uri.empty())
1370- d->parent->open_uri(uri);
1371- }
1372- });
1373-
1374- d->engine->seeked_to_signal().connect([this](uint64_t value)
1375- {
1376- seeked_to()(value);
1377- });
1378-
1379- d->engine->end_of_stream_signal().connect([this]()
1380- {
1381- end_of_stream()();
1382- });
1383-
1384- d->engine->playback_status_changed_signal().connect([this](const Player::PlaybackStatus& status)
1385- {
1386- playback_status_changed()(status);
1387- });
1388+ d->setup_connections_to_engine(*d->configuration.engine);
1389 }
1390
1391 media::PlayerImplementation::~PlayerImplementation()
1392@@ -262,23 +412,23 @@
1393
1394 std::shared_ptr<media::TrackList> media::PlayerImplementation::track_list()
1395 {
1396- return d->track_list;
1397+ return d->configuration.track_list;
1398 }
1399
1400 // TODO: Convert this to be a property instead of sync call
1401 media::Player::PlayerKey media::PlayerImplementation::key() const
1402 {
1403- return d->key;
1404+ return d->configuration.key;
1405 }
1406
1407 bool media::PlayerImplementation::open_uri(const Track::UriType& uri)
1408 {
1409- return d->engine->open_resource_for_uri(uri);
1410+ return d->configuration.engine->open_resource_for_uri(uri);
1411 }
1412
1413 void media::PlayerImplementation::create_video_sink(uint32_t texture_id)
1414 {
1415- d->engine->create_video_sink(texture_id);
1416+ d->configuration.engine->create_video_sink(texture_id);
1417 }
1418
1419 media::Player::GLConsumerWrapperHybris media::PlayerImplementation::gl_consumer() const
1420@@ -297,17 +447,17 @@
1421
1422 void media::PlayerImplementation::play()
1423 {
1424- d->engine->play();
1425+ d->configuration.engine->play();
1426 }
1427
1428 void media::PlayerImplementation::pause()
1429 {
1430- d->engine->pause();
1431+ d->configuration.engine->pause();
1432 }
1433
1434 void media::PlayerImplementation::stop()
1435 {
1436- d->engine->stop();
1437+ d->configuration.engine->stop();
1438 }
1439
1440 void media::PlayerImplementation::set_frame_available_callback(
1441@@ -324,5 +474,5 @@
1442
1443 void media::PlayerImplementation::seek_to(const std::chrono::microseconds& ms)
1444 {
1445- d->engine->seek_to(ms);
1446+ d->configuration.engine->seek_to(ms);
1447 }
1448
1449=== modified file 'src/core/media/player_implementation.h'
1450--- src/core/media/player_implementation.h 2014-04-25 17:53:00 +0000
1451+++ src/core/media/player_implementation.h 2014-07-07 14:32:42 +0000
1452@@ -35,10 +35,38 @@
1453 class PlayerImplementation : public PlayerSkeleton
1454 {
1455 public:
1456- PlayerImplementation(
1457- const core::dbus::types::ObjectPath& session_path,
1458- const std::shared_ptr<Service>& service,
1459- PlayerKey key);
1460+ // The name of the wake-lock we request from powerd.
1461+ static constexpr const char* wake_lock_name
1462+ {
1463+ "media-hub-music-playback"
1464+ };
1465+
1466+ // All creation time options go here.
1467+ struct Configuration
1468+ {
1469+ // The configuration object of the parent class.
1470+ PlayerSkeleton::Configuration skeleton_configuration;
1471+ // The unique key identifying the instance.
1472+ PlayerKey key;
1473+ // The engine implementation.
1474+ std::shared_ptr<Engine> engine;
1475+ // The track list implementation.
1476+ std::shared_ptr<TrackList> track_list;
1477+ // We have to interact with the system bus.
1478+ core::dbus::Bus::Ptr system_bus;
1479+ // We have to talk to bluez to wire up the players to bluetooth
1480+ core::dbus::Service::Ptr bluez;
1481+ // Used to query the default bluetooth adapter.
1482+ core::dbus::Object::Ptr bluez_manager;
1483+ // Used to announce the player instance.
1484+ core::dbus::Object::Ptr bluez_media;
1485+ // And we have to talk to powerd to make sure that the display
1486+ // stays on if video playback is active.
1487+ core::dbus::Object::Ptr powerd_session;
1488+ core::dbus::Object::Ptr uscreen_session;
1489+ };
1490+
1491+ PlayerImplementation(const Configuration& configuration);
1492 ~PlayerImplementation();
1493
1494 virtual std::shared_ptr<TrackList> track_list();
1495
1496=== added file 'src/core/media/player_p.h'
1497--- src/core/media/player_p.h 1970-01-01 00:00:00 +0000
1498+++ src/core/media/player_p.h 2014-07-07 14:32:42 +0000
1499@@ -0,0 +1,62 @@
1500+/*
1501+ * Copyright © 2013 Canonical Ltd.
1502+ *
1503+ * This program is free software: you can redistribute it and/or modify it
1504+ * under the terms of the GNU Lesser General Public License version 3,
1505+ * as published by the Free Software Foundation.
1506+ *
1507+ * This program is distributed in the hope that it will be useful,
1508+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1509+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1510+ * GNU Lesser General Public License for more details.
1511+ *
1512+ * You should have received a copy of the GNU Lesser General Public License
1513+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1514+ *
1515+ * Authored by: Thomas Voß <thomas.voss@canonical.com>
1516+ */
1517+
1518+#ifndef CORE_MEDIA_PLAYER_PRIVATE_H_
1519+#define CORE_MEDIA_PLAYER_PRIVATE_H_
1520+
1521+#include "mpris/media_player2.h"
1522+#include "mpris/player.h"
1523+
1524+#include <core/dbus/traits/service.h>
1525+
1526+namespace core
1527+{
1528+namespace dbus
1529+{
1530+namespace traits
1531+{
1532+template<>
1533+struct Service<mpris::Player<core::ubuntu::media::Player>>
1534+{
1535+ inline static const std::string& interface_name()
1536+ {
1537+ static const std::string s
1538+ {
1539+ "org.mpris.MediaPlayer2.MediaHub"
1540+ };
1541+ return s;
1542+ }
1543+};
1544+
1545+template<>
1546+struct Service<mpris::Player<mpris::MediaPlayer2>>
1547+{
1548+ static std::string interface_name()
1549+ {
1550+ static const std::string base_service_name{"org.mpris.MediaPlayer2.instance"};
1551+ // Incrementing counter for distinguishing instances.
1552+ static std::uint32_t counter{0};
1553+
1554+ return base_service_name + std::to_string(counter++);
1555+ }
1556+};
1557+}
1558+}
1559+}
1560+
1561+#endif // CORE_MEDIA_PLAYER_PRIVATE_H_
1562
1563=== modified file 'src/core/media/player_skeleton.cpp'
1564--- src/core/media/player_skeleton.cpp 2014-05-21 08:25:44 +0000
1565+++ src/core/media/player_skeleton.cpp 2014-07-07 14:32:42 +0000
1566@@ -18,350 +18,102 @@
1567
1568 #include "apparmor.h"
1569 #include "codec.h"
1570+#include "player_p.h"
1571 #include "player_skeleton.h"
1572 #include "player_traits.h"
1573 #include "property_stub.h"
1574 #include "the_session_bus.h"
1575
1576-#include "mpris/player.h"
1577-
1578 #include <core/dbus/object.h>
1579 #include <core/dbus/property.h>
1580 #include <core/dbus/stub.h>
1581 #include <core/dbus/asio/executor.h>
1582+#include <core/dbus/traits/service.h>
1583
1584 namespace dbus = core::dbus;
1585 namespace media = core::ubuntu::media;
1586
1587-struct media::PlayerSkeleton::Private
1588-{
1589- Private(media::PlayerSkeleton* player, const dbus::types::ObjectPath& session)
1590- : impl(player),
1591- object(impl->access_service()->add_object_for_path(session)),
1592- apparmor_session(nullptr),
1593- properties
1594+namespace core
1595+{
1596+namespace dbus
1597+{
1598+namespace traits
1599+{
1600+template<> struct Service<mpris::MediaPlayer2>
1601+{
1602+ static std::string interface_name()
1603+ {
1604+ return "org.mpris.MediaPlayer2";
1605+ }
1606+};
1607+}
1608+}
1609+}
1610+
1611+namespace
1612+{
1613+std::uint32_t instance_counter{0};
1614+std::string service_base_name{"org.mpris.MediaPlayer2.umh.instance"};
1615+}
1616+
1617+media::PlayerSkeleton::PlayerSkeleton(const media::PlayerSkeleton::Configuration& config)
1618+ : configuration(config),
1619+ client_skeleton
1620 {
1621- object->get_property<mpris::Player::Properties::CanPlay>(),
1622- object->get_property<mpris::Player::Properties::CanPause>(),
1623- object->get_property<mpris::Player::Properties::CanSeek>(),
1624- object->get_property<mpris::Player::Properties::CanControl>(),
1625- object->get_property<mpris::Player::Properties::CanGoNext>(),
1626- object->get_property<mpris::Player::Properties::CanGoPrevious>(),
1627- object->get_property<mpris::Player::Properties::IsVideoSource>(),
1628- object->get_property<mpris::Player::Properties::IsAudioSource>(),
1629- object->get_property<mpris::Player::Properties::PlaybackStatus>(),
1630- object->get_property<mpris::Player::Properties::LoopStatus>(),
1631- object->get_property<mpris::Player::Properties::PlaybackRate>(),
1632- object->get_property<mpris::Player::Properties::Shuffle>(),
1633- object->get_property<mpris::Player::Properties::MetaData>(),
1634- object->get_property<mpris::Player::Properties::Volume>(),
1635- object->get_property<mpris::Player::Properties::Position>(),
1636- object->get_property<mpris::Player::Properties::Duration>(),
1637- object->get_property<mpris::Player::Properties::MinimumRate>(),
1638- object->get_property<mpris::Player::Properties::MaximumRate>()
1639+ mpris::Player<core::ubuntu::media::Player>::Skeleton::Configuration
1640+ {
1641+ config.bus,
1642+ config.object,
1643+ [this](const core::dbus::Message::Ptr& in) { return handle_next(in); },
1644+ [this](const core::dbus::Message::Ptr& in) { return handle_previous(in); },
1645+ [this](const core::dbus::Message::Ptr& in) { return handle_pause(in); },
1646+ [this](const core::dbus::Message::Ptr& in) { return handle_stop(in); },
1647+ [this](const core::dbus::Message::Ptr& in) { return handle_play(in); },
1648+ [this](const core::dbus::Message::Ptr& in) { return handle_seek(in); },
1649+ [this](const core::dbus::Message::Ptr& in) { return handle_create_video_sink(in); },
1650+ [this](const core::dbus::Message::Ptr& in) { return handle_key(in); },
1651+ [this](const core::dbus::Message::Ptr& in) { return handle_open_uri(in); }
1652+ }
1653 },
1654- signals
1655+ mpris_skeleton
1656 {
1657- object->get_signal<mpris::Player::Signals::Seeked>(),
1658- object->get_signal<mpris::Player::Signals::EndOfStream>(),
1659- object->get_signal<mpris::Player::Signals::PlaybackStatusChanged>()
1660+ MprisSkeleton::Configuration
1661+ {
1662+ configuration.bus,
1663+ core::dbus::Service::add_service(configuration.bus, service_base_name + std::to_string(instance_counter++)),
1664+ [this](const core::dbus::Message::Ptr& in) { return handle_next(in); },
1665+ [this](const core::dbus::Message::Ptr& in) { return handle_previous(in); },
1666+ [this](const core::dbus::Message::Ptr& in) { return handle_pause(in); },
1667+ [this](const core::dbus::Message::Ptr& in) { return handle_stop(in); },
1668+ [this](const core::dbus::Message::Ptr& in) { return handle_play(in); }
1669+ }
1670 }
1671- {
1672- }
1673-
1674- void handle_next(const core::dbus::Message::Ptr& msg)
1675- {
1676- impl->next();
1677- auto reply = dbus::Message::make_method_return(msg);
1678- impl->access_bus()->send(reply);
1679- }
1680-
1681- void handle_previous(const core::dbus::Message::Ptr& msg)
1682- {
1683- impl->previous();
1684- auto reply = dbus::Message::make_method_return(msg);
1685- impl->access_bus()->send(reply);
1686- }
1687-
1688- void handle_pause(const core::dbus::Message::Ptr& msg)
1689- {
1690- impl->pause();
1691- auto reply = dbus::Message::make_method_return(msg);
1692- impl->access_bus()->send(reply);
1693- }
1694-
1695- void handle_playpause(DBusMessage*)
1696- {
1697- }
1698-
1699- void handle_stop(const core::dbus::Message::Ptr& msg)
1700- {
1701- impl->stop();
1702- auto reply = dbus::Message::make_method_return(msg);
1703- impl->access_bus()->send(reply);
1704- }
1705-
1706- void handle_play(const core::dbus::Message::Ptr& msg)
1707- {
1708- impl->play();
1709- auto reply = dbus::Message::make_method_return(msg);
1710- impl->access_bus()->send(reply);
1711- }
1712-
1713- void handle_seek(const core::dbus::Message::Ptr& in)
1714- {
1715- uint64_t ticks;
1716- in->reader() >> ticks;
1717- impl->seek_to(std::chrono::microseconds(ticks));
1718-
1719- auto reply = dbus::Message::make_method_return(in);
1720- impl->access_bus()->send(reply);
1721- }
1722-
1723- void handle_set_position(const core::dbus::Message::Ptr&)
1724- {
1725- }
1726-
1727- void handle_create_video_sink(const core::dbus::Message::Ptr& in)
1728- {
1729- uint32_t texture_id;
1730- in->reader() >> texture_id;
1731- impl->create_video_sink(texture_id);
1732-
1733- auto reply = dbus::Message::make_method_return(in);
1734- impl->access_bus()->send(reply);
1735- }
1736-
1737- std::string get_client_apparmor_context(const core::dbus::Message::Ptr& msg)
1738- {
1739- auto bus = std::shared_ptr<dbus::Bus>(new dbus::Bus(core::dbus::WellKnownBus::session));
1740- bus->install_executor(dbus::asio::make_executor(bus));
1741-
1742- auto stub_service = dbus::Service::use_service(bus, dbus::traits::Service<core::Apparmor>::interface_name());
1743- apparmor_session = stub_service->object_for_path(dbus::types::ObjectPath("/org/freedesktop/DBus"));
1744- // Get the AppArmor security context for the client
1745- auto result = apparmor_session->invoke_method_synchronously<core::Apparmor::getConnectionAppArmorSecurityContext, std::string>(msg->sender());
1746- if (result.is_error())
1747- {
1748- std::cout << "Error getting apparmor profile: " << result.error().print() << std::endl;
1749- return std::string();
1750- }
1751-
1752- return result.value();
1753- }
1754-
1755- bool does_client_have_access(const std::string& context, const std::string& uri)
1756- {
1757- if (context.empty() || uri.empty())
1758- {
1759- std::cout << "Client denied access since context or uri are empty" << std::endl;
1760- return false;
1761- }
1762-
1763- if (context == "unconfined")
1764- {
1765- std::cout << "Client allowed access since it's unconfined" << std::endl;
1766- return true;
1767- }
1768-
1769- size_t pos = context.find_first_of('_');
1770- if (pos == std::string::npos)
1771- {
1772- std::cout << "Client denied access since it's an invalid apparmor security context" << std::endl;
1773- return false;
1774- }
1775-
1776- const std::string pkgname = context.substr(0, pos);
1777- std::cout << "client pkgname: " << pkgname << std::endl;
1778- std::cout << "uri: " << uri << std::endl;
1779-
1780- // All confined apps can access their own files
1781- if (uri.find(std::string(".local/share/" + pkgname + "/")) != std::string::npos
1782- || uri.find(std::string(".cache/" + pkgname + "/")) != std::string::npos)
1783- {
1784- std::cout << "Client can access content in ~/.local/share/" << pkgname << " or ~/.cache/" << pkgname << std::endl;
1785- return true;
1786- }
1787- else if (uri.find(std::string("opt/click.ubuntu.com/")) != std::string::npos
1788- && uri.find(pkgname) != std::string::npos)
1789- {
1790- std::cout << "Client can access content in own opt directory" << std::endl;
1791- return true;
1792- }
1793- else if ((uri.find(std::string("/system/media/audio/ui/")) != std::string::npos
1794- || uri.find(std::string("/android/system/media/audio/ui/")) != std::string::npos)
1795- && pkgname == "com.ubuntu.camera")
1796- {
1797- std::cout << "Camera app can access ui sounds" << std::endl;
1798- return true;
1799- }
1800- // TODO: Check if the trust store previously allowed direct access to uri
1801-
1802- // Check in ~/Music and ~/Videos
1803- // TODO: when the trust store lands, check it to see if this app can access the dirs and
1804- // then remove the explicit whitelist of the music-app, and gallery-app
1805- else if ((pkgname == "com.ubuntu.music" || pkgname == "com.ubuntu.gallery") &&
1806- (uri.find(std::string("Music/")) != std::string::npos
1807- || uri.find(std::string("Videos/")) != std::string::npos))
1808- {
1809- std::cout << "Client can access content in ~/Music or ~/Videos" << std::endl;
1810- return true;
1811- }
1812- else if (uri.find(std::string("http://")) != std::string::npos
1813- || uri.find(std::string("rtsp://")) != std::string::npos)
1814- {
1815- std::cout << "Client can access streaming content" << std::endl;
1816- return true;
1817- }
1818- else
1819- {
1820- std::cout << "Client denied access to open_uri()" << std::endl;
1821- return false;
1822- }
1823- }
1824-
1825- void handle_key(const core::dbus::Message::Ptr& in)
1826- {
1827- auto reply = dbus::Message::make_method_return(in);
1828- reply->writer() << impl->key();
1829- impl->access_bus()->send(reply);
1830- }
1831-
1832- void handle_open_uri(const core::dbus::Message::Ptr& in)
1833- {
1834- Track::UriType uri;
1835- in->reader() >> uri;
1836-
1837- std::string context = get_client_apparmor_context(in);
1838- bool have_access = does_client_have_access(context, uri);
1839-
1840- auto reply = dbus::Message::make_method_return(in);
1841- if (have_access)
1842- reply->writer() << impl->open_uri(uri);
1843- else
1844- reply->writer() << false;
1845- impl->access_bus()->send(reply);
1846- }
1847-
1848- media::PlayerSkeleton* impl;
1849- dbus::Object::Ptr object;
1850- dbus::Object::Ptr apparmor_session;
1851- struct
1852- {
1853- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanPlay>> can_play;
1854- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanPause>> can_pause;
1855- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanSeek>> can_seek;
1856- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanControl>> can_control;
1857- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanGoNext>> can_go_next;
1858- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanGoPrevious>> can_go_previous;
1859- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::IsVideoSource>> is_video_source;
1860- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::IsAudioSource>> is_audio_source;
1861-
1862- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::PlaybackStatus>> playback_status;
1863- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::LoopStatus>> loop_status;
1864- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::PlaybackRate>> playback_rate;
1865- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Shuffle>> is_shuffle;
1866- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MetaData>> meta_data_for_current_track;
1867- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Volume>> volume;
1868- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Position>> position;
1869- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Duration>> duration;
1870- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MinimumRate>> minimum_playback_rate;
1871- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MaximumRate>> maximum_playback_rate;
1872- } properties;
1873-
1874- struct Signals
1875- {
1876- typedef core::dbus::Signal<mpris::Player::Signals::Seeked, mpris::Player::Signals::Seeked::ArgumentType> DBusSeekedToSignal;
1877- typedef core::dbus::Signal<mpris::Player::Signals::EndOfStream, mpris::Player::Signals::EndOfStream::ArgumentType> DBusEndOfStreamSignal;
1878- typedef core::dbus::Signal<mpris::Player::Signals::PlaybackStatusChanged, mpris::Player::Signals::PlaybackStatusChanged::ArgumentType> DBusPlaybackStatusChangedSignal;
1879-
1880- Signals(const std::shared_ptr<DBusSeekedToSignal>& seeked,
1881- const std::shared_ptr<DBusEndOfStreamSignal>& eos,
1882- const std::shared_ptr<DBusPlaybackStatusChangedSignal>& status)
1883- : dbus
1884- {
1885- seeked,
1886- eos,
1887- status
1888- },
1889- seeked_to(),
1890- end_of_stream(),
1891- playback_status_changed()
1892- {
1893- seeked_to.connect([this](std::uint64_t value)
1894- {
1895- dbus.seeked_to->emit(value);
1896- });
1897-
1898- end_of_stream.connect([this]()
1899- {
1900- dbus.end_of_stream->emit();
1901- });
1902-
1903- playback_status_changed.connect([this](const media::Player::PlaybackStatus& status)
1904- {
1905- dbus.playback_status_changed->emit(status);
1906- });
1907- }
1908-
1909- struct DBus
1910- {
1911- std::shared_ptr<DBusSeekedToSignal> seeked_to;
1912- std::shared_ptr<DBusEndOfStreamSignal> end_of_stream;
1913- std::shared_ptr<DBusPlaybackStatusChangedSignal> playback_status_changed;
1914- } dbus;
1915- core::Signal<uint64_t> seeked_to;
1916- core::Signal<void> end_of_stream;
1917- core::Signal<media::Player::PlaybackStatus> playback_status_changed;
1918- } signals;
1919-
1920-};
1921-
1922-media::PlayerSkeleton::PlayerSkeleton(
1923- const core::dbus::types::ObjectPath& session_path)
1924- : dbus::Skeleton<media::Player>(the_session_bus()),
1925- d(new Private{this, session_path})
1926 {
1927- d->object->install_method_handler<mpris::Player::Next>(
1928- std::bind(&Private::handle_next,
1929- std::ref(d),
1930- std::placeholders::_1));
1931- d->object->install_method_handler<mpris::Player::Previous>(
1932- std::bind(&Private::handle_previous,
1933- std::ref(d),
1934- std::placeholders::_1));
1935- d->object->install_method_handler<mpris::Player::Pause>(
1936- std::bind(&Private::handle_pause,
1937- std::ref(d),
1938- std::placeholders::_1));
1939- d->object->install_method_handler<mpris::Player::Stop>(
1940- std::bind(&Private::handle_stop,
1941- std::ref(d),
1942- std::placeholders::_1));
1943- d->object->install_method_handler<mpris::Player::Play>(
1944- std::bind(&Private::handle_play,
1945- std::ref(d),
1946- std::placeholders::_1));
1947- d->object->install_method_handler<mpris::Player::Seek>(
1948- std::bind(&Private::handle_seek,
1949- std::ref(d),
1950- std::placeholders::_1));
1951- d->object->install_method_handler<mpris::Player::SetPosition>(
1952- std::bind(&Private::handle_set_position,
1953- std::ref(d),
1954- std::placeholders::_1));
1955- d->object->install_method_handler<mpris::Player::CreateVideoSink>(
1956- std::bind(&Private::handle_create_video_sink,
1957- std::ref(d),
1958- std::placeholders::_1));
1959- d->object->install_method_handler<mpris::Player::Key>(
1960- std::bind(&Private::handle_key,
1961- std::ref(d),
1962- std::placeholders::_1));
1963- d->object->install_method_handler<mpris::Player::OpenUri>(
1964- std::bind(&Private::handle_open_uri,
1965- std::ref(d),
1966- std::placeholders::_1));
1967+ // Wire up local -> remote signal propagation
1968+ signals.seeked_to.connect([this](std::uint64_t value)
1969+ {
1970+ client_skeleton.signals.seeked_to->emit(value);
1971+ });
1972+
1973+ signals.end_of_stream.connect([this]()
1974+ {
1975+ client_skeleton.signals.end_of_stream->emit();
1976+ });
1977+
1978+ signals.playback_status_changed.connect([this](const media::Player::PlaybackStatus& status)
1979+ {
1980+ client_skeleton.signals.playback_status_changed->emit(status);
1981+ });
1982+
1983+ playback_status().changed().connect([this](core::ubuntu::media::Player::PlaybackStatus status)
1984+ {
1985+ mpris_skeleton.player.properties.playback_status->set(mpris::Player<mpris::MediaPlayer2>::PlaybackStatus::from(status));
1986+ });
1987+
1988+ position().changed().connect([this](std::uint64_t pos)
1989+ {
1990+ mpris_skeleton.player.properties.position->set(pos);
1991+ });
1992 }
1993
1994 media::PlayerSkeleton::~PlayerSkeleton()
1995@@ -370,196 +122,347 @@
1996
1997 const core::Property<bool>& media::PlayerSkeleton::can_play() const
1998 {
1999- return *d->properties.can_play;
2000+ return *client_skeleton.properties.can_play;
2001 }
2002
2003 const core::Property<bool>& media::PlayerSkeleton::can_pause() const
2004 {
2005- return *d->properties.can_pause;
2006+ return *client_skeleton.properties.can_pause;
2007 }
2008
2009 const core::Property<bool>& media::PlayerSkeleton::can_seek() const
2010 {
2011- return *d->properties.can_seek;
2012+ return *client_skeleton.properties.can_seek;
2013 }
2014
2015 const core::Property<bool>& media::PlayerSkeleton::can_go_previous() const
2016 {
2017- return *d->properties.can_go_previous;
2018+ return *client_skeleton.properties.can_go_previous;
2019 }
2020
2021 const core::Property<bool>& media::PlayerSkeleton::can_go_next() const
2022 {
2023- return *d->properties.can_go_next;
2024+ return *client_skeleton.properties.can_go_next;
2025 }
2026
2027 const core::Property<bool>& media::PlayerSkeleton::is_video_source() const
2028 {
2029- return *d->properties.is_video_source;
2030+ return *client_skeleton.properties.is_video_source;
2031 }
2032
2033 const core::Property<bool>& media::PlayerSkeleton::is_audio_source() const
2034 {
2035- return *d->properties.is_audio_source;
2036+ return *client_skeleton.properties.is_audio_source;
2037 }
2038
2039 const core::Property<media::Player::PlaybackStatus>& media::PlayerSkeleton::playback_status() const
2040 {
2041- return *d->properties.playback_status;
2042+ return *client_skeleton.properties.typed_playback_status;
2043 }
2044
2045 const core::Property<media::Player::LoopStatus>& media::PlayerSkeleton::loop_status() const
2046 {
2047- return *d->properties.loop_status;
2048+ return *client_skeleton.properties.typed_loop_status;
2049 }
2050
2051 const core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::playback_rate() const
2052 {
2053- return *d->properties.playback_rate;
2054+ return *client_skeleton.properties.playback_rate;
2055 }
2056
2057 const core::Property<bool>& media::PlayerSkeleton::is_shuffle() const
2058 {
2059- return *d->properties.is_shuffle;
2060+ return *client_skeleton.properties.is_shuffle;
2061 }
2062
2063 const core::Property<media::Track::MetaData>& media::PlayerSkeleton::meta_data_for_current_track() const
2064 {
2065- return *d->properties.meta_data_for_current_track;
2066+ return *client_skeleton.properties.meta_data_for_current_track;
2067 }
2068
2069 const core::Property<media::Player::Volume>& media::PlayerSkeleton::volume() const
2070 {
2071- return *d->properties.volume;
2072+ return *client_skeleton.properties.volume;
2073 }
2074
2075 const core::Property<uint64_t>& media::PlayerSkeleton::position() const
2076 {
2077- return *d->properties.position;
2078+ return *client_skeleton.properties.position;
2079 }
2080
2081 const core::Property<uint64_t>& media::PlayerSkeleton::duration() const
2082 {
2083- return *d->properties.duration;
2084+ return *client_skeleton.properties.duration;
2085 }
2086
2087 const core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::minimum_playback_rate() const
2088 {
2089- return *d->properties.minimum_playback_rate;
2090+ return *client_skeleton.properties.minimum_playback_rate;
2091 }
2092
2093 const core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::maximum_playback_rate() const
2094 {
2095- return *d->properties.maximum_playback_rate;
2096+ return *client_skeleton.properties.maximum_playback_rate;
2097 }
2098
2099 core::Property<media::Player::LoopStatus>& media::PlayerSkeleton::loop_status()
2100 {
2101- return *d->properties.loop_status;
2102+ return *client_skeleton.properties.typed_loop_status;
2103 }
2104
2105 core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::playback_rate()
2106 {
2107- return *d->properties.playback_rate;
2108+ return *client_skeleton.properties.playback_rate;
2109 }
2110
2111 core::Property<bool>& media::PlayerSkeleton::is_shuffle()
2112 {
2113- return *d->properties.is_shuffle;
2114+ return *client_skeleton.properties.is_shuffle;
2115 }
2116
2117 core::Property<media::Player::Volume>& media::PlayerSkeleton::volume()
2118 {
2119- return *d->properties.volume;
2120+ return *client_skeleton.properties.volume;
2121 }
2122
2123 core::Property<uint64_t>& media::PlayerSkeleton::position()
2124 {
2125- return *d->properties.position;
2126+ return *client_skeleton.properties.position;
2127 }
2128
2129 core::Property<uint64_t>& media::PlayerSkeleton::duration()
2130 {
2131- return *d->properties.duration;
2132+ return *client_skeleton.properties.duration;
2133 }
2134
2135 core::Property<media::Player::PlaybackStatus>& media::PlayerSkeleton::playback_status()
2136 {
2137- return *d->properties.playback_status;
2138+ return *client_skeleton.properties.typed_playback_status;
2139 }
2140
2141 core::Property<bool>& media::PlayerSkeleton::can_play()
2142 {
2143- return *d->properties.can_play;
2144+ return *client_skeleton.properties.can_play;
2145 }
2146
2147 core::Property<bool>& media::PlayerSkeleton::can_pause()
2148 {
2149- return *d->properties.can_pause;
2150+ return *client_skeleton.properties.can_pause;
2151 }
2152
2153 core::Property<bool>& media::PlayerSkeleton::can_seek()
2154 {
2155- return *d->properties.can_seek;
2156+ return *client_skeleton.properties.can_seek;
2157 }
2158
2159 core::Property<bool>& media::PlayerSkeleton::can_go_previous()
2160 {
2161- return *d->properties.can_go_previous;
2162+ return *client_skeleton.properties.can_go_previous;
2163 }
2164
2165 core::Property<bool>& media::PlayerSkeleton::can_go_next()
2166 {
2167- return *d->properties.can_go_next;
2168+ return *client_skeleton.properties.can_go_next;
2169 }
2170
2171 core::Property<bool>& media::PlayerSkeleton::is_video_source()
2172 {
2173- return *d->properties.is_video_source;
2174+ return *client_skeleton.properties.is_video_source;
2175 }
2176
2177 core::Property<bool>& media::PlayerSkeleton::is_audio_source()
2178 {
2179- return *d->properties.is_audio_source;
2180+ return *client_skeleton.properties.is_audio_source;
2181 }
2182
2183-
2184 core::Property<media::Track::MetaData>& media::PlayerSkeleton::meta_data_for_current_track()
2185 {
2186- return *d->properties.meta_data_for_current_track;
2187+ return *client_skeleton.properties.meta_data_for_current_track;
2188 }
2189
2190 core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::minimum_playback_rate()
2191 {
2192- return *d->properties.minimum_playback_rate;
2193+ return *client_skeleton.properties.minimum_playback_rate;
2194 }
2195
2196 core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::maximum_playback_rate()
2197 {
2198- return *d->properties.maximum_playback_rate;
2199+ return *client_skeleton.properties.maximum_playback_rate;
2200 }
2201
2202 const core::Signal<uint64_t>& media::PlayerSkeleton::seeked_to() const
2203 {
2204- return d->signals.seeked_to;
2205+ return signals.seeked_to;
2206 }
2207
2208 core::Signal<uint64_t>& media::PlayerSkeleton::seeked_to()
2209 {
2210- return d->signals.seeked_to;
2211+ return signals.seeked_to;
2212 }
2213
2214 const core::Signal<void>& media::PlayerSkeleton::end_of_stream() const
2215 {
2216- return d->signals.end_of_stream;
2217+ return signals.end_of_stream;
2218 }
2219
2220 core::Signal<void>& media::PlayerSkeleton::end_of_stream()
2221 {
2222- return d->signals.end_of_stream;
2223+ return signals.end_of_stream;
2224 }
2225
2226 core::Signal<media::Player::PlaybackStatus>& media::PlayerSkeleton::playback_status_changed()
2227 {
2228- return d->signals.playback_status_changed;
2229+ return signals.playback_status_changed;
2230+}
2231+
2232+// Private functions
2233+core::dbus::Message::Ptr media::PlayerSkeleton::handle_next(const core::dbus::Message::Ptr& msg)
2234+{
2235+ next();
2236+ return dbus::Message::make_method_return(msg);
2237+}
2238+
2239+core::dbus::Message::Ptr media::PlayerSkeleton::handle_previous(const core::dbus::Message::Ptr& msg)
2240+{
2241+ previous();
2242+ return dbus::Message::make_method_return(msg);
2243+}
2244+
2245+core::dbus::Message::Ptr media::PlayerSkeleton::handle_pause(const core::dbus::Message::Ptr& msg)
2246+{
2247+ pause();
2248+ return dbus::Message::make_method_return(msg);
2249+}
2250+
2251+core::dbus::Message::Ptr media::PlayerSkeleton::handle_stop(const core::dbus::Message::Ptr& msg)
2252+{
2253+ stop();
2254+ return dbus::Message::make_method_return(msg);
2255+}
2256+
2257+core::dbus::Message::Ptr media::PlayerSkeleton::handle_play(const core::dbus::Message::Ptr& msg)
2258+{
2259+ play();
2260+ return dbus::Message::make_method_return(msg);
2261+}
2262+
2263+core::dbus::Message::Ptr media::PlayerSkeleton::handle_seek(const core::dbus::Message::Ptr& in)
2264+{
2265+ uint64_t ticks;
2266+ in->reader() >> ticks;
2267+ seek_to(std::chrono::microseconds(ticks));
2268+
2269+ return dbus::Message::make_method_return(in);
2270+}
2271+
2272+core::dbus::Message::Ptr media::PlayerSkeleton::handle_create_video_sink(const core::dbus::Message::Ptr& in)
2273+{
2274+ uint32_t texture_id;
2275+ in->reader() >> texture_id;
2276+ create_video_sink(texture_id);
2277+
2278+ return dbus::Message::make_method_return(in);
2279+}
2280+
2281+core::dbus::Message::Ptr media::PlayerSkeleton::handle_key(const core::dbus::Message::Ptr& in)
2282+{
2283+ auto reply = dbus::Message::make_method_return(in);
2284+ reply->writer() << key();
2285+ return reply;
2286+}
2287+
2288+core::dbus::Message::Ptr media::PlayerSkeleton::handle_open_uri(const core::dbus::Message::Ptr& in)
2289+{
2290+ Track::UriType uri;
2291+ in->reader() >> uri;
2292+
2293+ // Let's first resolve the credentials of the caller.
2294+ bool have_access = configuration.is_client_with_credentials_allowed_to_access_uri(
2295+ configuration.resolve_incoming_msg_to_client_credentials(in), uri);
2296+
2297+ core::dbus::Message::Ptr reply;
2298+
2299+ if (have_access)
2300+ {
2301+ reply = dbus::Message::make_method_return(in);
2302+ reply->writer() << open_uri(uri);
2303+ } else
2304+ {
2305+ reply = dbus::Message::make_error(in, "core.ubuntu.media.Error.Permission", "Not allowed to access: " + uri);
2306+ }
2307+
2308+ return reply;
2309+}
2310+
2311+media::PlayerSkeleton::MprisSkeleton::MprisSkeleton(const media::PlayerSkeleton::MprisSkeleton::Configuration& config)
2312+ : configuration(config),
2313+ object
2314+ {
2315+ config.service->add_object_for_path_with_policy(
2316+ core::dbus::types::ObjectPath{"/org/mpris/MediaPlayer2"},
2317+ core::dbus::immediate_announcement_property_changed_policy())
2318+ },
2319+ media_player2
2320+ {
2321+ mpris::MediaPlayer2::Skeleton::Configuration
2322+ {
2323+ configuration.bus,
2324+ object,
2325+ // We return errors for raise requests
2326+ mpris::MediaPlayer2::Skeleton::Configuration::a_handler_returning_error(),
2327+ // We return errors for quit requests
2328+ mpris::MediaPlayer2::Skeleton::Configuration::a_handler_returning_error()
2329+ }
2330+ },
2331+ player
2332+ {
2333+ mpris::Player<mpris::MediaPlayer2>::Skeleton::Configuration
2334+ {
2335+ configuration.bus,
2336+ object,
2337+ config.handle_next,
2338+ config.handle_previous,
2339+ config.handle_pause,
2340+ config.handle_stop,
2341+ config.handle_play,
2342+ // We return errors for seek requests
2343+ mpris::MediaPlayer2::Skeleton::Configuration::a_handler_returning_error(),
2344+ // We return errors for create video sink requests
2345+ mpris::MediaPlayer2::Skeleton::Configuration::a_handler_returning_error(),
2346+ // We return errors for key generation requests
2347+ mpris::MediaPlayer2::Skeleton::Configuration::a_handler_returning_error(),
2348+ // We return erros for open uri requests
2349+ mpris::MediaPlayer2::Skeleton::Configuration::a_handler_returning_error(),
2350+ }
2351+ }
2352+{
2353+ // Report general capabilities here.
2354+ media_player2.properties.can_quit->set(false);
2355+ media_player2.properties.can_raise->set(false);
2356+ media_player2.properties.can_set_fullscreen->set(false);
2357+ media_player2.properties.has_track_list->set(true);
2358+
2359+ // And the rest of the properties are initialized here.
2360+ media_player2.properties.identity->set("Ubuntu Media Hub");
2361+ // Just for testing purposes.
2362+ media_player2.properties.desktop_entry->set("mediaplayer-app");
2363+ // We report an empty list of mimetypes.
2364+ // TODO(tvoss): We should query this information from the underlying engine.
2365+ media_player2.properties.supported_mime_types->set({""});
2366+ // And an empty list of supported uri schemes
2367+ media_player2.properties.supported_uri_schemes->set({""});
2368+
2369+ // Initialize all the capabilities of the player instance.
2370+ player.properties.can_play->set(true);
2371+ player.properties.can_pause->set(true);
2372+ player.properties.can_seek->set(true);
2373+ player.properties.can_control->set(true);
2374+ player.properties.can_go_next->set(true);
2375+ player.properties.can_go_previous->set(true);
2376+
2377+ player.properties.playback_status->set(mpris::Player<mpris::MediaPlayer2>::PlaybackStatus::stopped);
2378+ player.properties.loop_status->set(mpris::Player<mpris::MediaPlayer2>::LoopStatus::none);
2379+ player.properties.playback_rate->set(1.f);
2380+ player.properties.is_shuffle->set(false);
2381+
2382 }
2383
2384=== modified file 'src/core/media/player_skeleton.h'
2385--- src/core/media/player_skeleton.h 2014-04-25 17:53:00 +0000
2386+++ src/core/media/player_skeleton.h 2014-07-07 14:32:42 +0000
2387@@ -23,12 +23,16 @@
2388
2389 #include "player_traits.h"
2390
2391+#include "mpris/media_player2.h"
2392 #include "mpris/player.h"
2393
2394+#include <core/dbus/object.h>
2395 #include <core/dbus/skeleton.h>
2396 #include <core/dbus/types/object_path.h>
2397
2398+#include <functional>
2399 #include <memory>
2400+#include <tuple>
2401
2402 namespace core
2403 {
2404@@ -38,11 +42,34 @@
2405 {
2406 class Service;
2407
2408-class PlayerSkeleton : public core::dbus::Skeleton<core::ubuntu::media::Player>
2409+class PlayerSkeleton : public core::ubuntu::media::Player
2410 {
2411- public:
2412+public:
2413+ // Functor resolving dbus message and its sender to
2414+ // process id, user id and apparmor confinement profile.
2415+ typedef std::function<std::tuple<pid_t, uid_t, std::string>(const core::dbus::Message::Ptr&)> CredentialsResolver;
2416+ // Functor returning false if the client corresponding to the credentials tuple
2417+ // is allowed to access the uri given as argument.
2418+ typedef std::function<bool(const std::tuple<pid_t, uid_t, std::string>&, const std::string&)> PermissionManager;
2419+
2420+ // Creation time options being passed to c'tor go here.
2421+ struct Configuration
2422+ {
2423+ // The outgoing bus connection for querying other services.
2424+ core::dbus::Bus::Ptr bus;
2425+ // Endpoint for mapping this instance to the bus.
2426+ core::dbus::Object::Ptr object;
2427+
2428+ // The functor called by the skeleton to resolve credentials.
2429+ CredentialsResolver resolve_incoming_msg_to_client_credentials;
2430+ // The functor called by the skeleton to verify if a client is allowed to access a uri.
2431+ PermissionManager is_client_with_credentials_allowed_to_access_uri;
2432+ };
2433+
2434+ PlayerSkeleton(const Configuration& configuration);
2435 ~PlayerSkeleton();
2436
2437+ // From com::ubuntu::media::Player
2438 virtual const core::Property<bool>& can_play() const;
2439 virtual const core::Property<bool>& can_pause() const;
2440 virtual const core::Property<bool>& can_seek() const;
2441@@ -70,8 +97,7 @@
2442 virtual const core::Signal<void>& end_of_stream() const;
2443 virtual core::Signal<PlaybackStatus>& playback_status_changed();
2444
2445- protected:
2446- PlayerSkeleton(const core::dbus::types::ObjectPath& session_path);
2447+protected:
2448
2449 virtual core::Property<PlaybackStatus>& playback_status();
2450 virtual core::Property<bool>& can_play();
2451@@ -90,9 +116,88 @@
2452 virtual core::Signal<uint64_t>& seeked_to();
2453 virtual core::Signal<void>& end_of_stream();
2454
2455- private:
2456- struct Private;
2457- std::unique_ptr<Private> d;
2458+private:
2459+ // Handles incoming calls for next. Never throws.
2460+ core::dbus::Message::Ptr handle_next(const core::dbus::Message::Ptr& msg);
2461+
2462+ // Handles incoming calls for previous. Never throws.
2463+ core::dbus::Message::Ptr handle_previous(const core::dbus::Message::Ptr& msg);
2464+
2465+ // Handles incoming calls for pause. Never throws.
2466+ core::dbus::Message::Ptr handle_pause(const core::dbus::Message::Ptr& msg);
2467+
2468+ // Handles incoming calls for stpo. Never throws.
2469+ core::dbus::Message::Ptr handle_stop(const core::dbus::Message::Ptr& msg);
2470+
2471+ // Handles incoming calls for play. Never throws.
2472+ core::dbus::Message::Ptr handle_play(const core::dbus::Message::Ptr& msg);
2473+
2474+ // Handles incoming calls for seek. Never throws.
2475+ core::dbus::Message::Ptr handle_seek(const core::dbus::Message::Ptr& in);
2476+
2477+ // Handles incoming calls for video sink creation. Never throws.
2478+ core::dbus::Message::Ptr handle_create_video_sink(const core::dbus::Message::Ptr& in);
2479+
2480+ // Handles incoming calls for key generation. Never throws.
2481+ core::dbus::Message::Ptr handle_key(const core::dbus::Message::Ptr& in);
2482+
2483+ // Handles incoming calls for opening a URI. Never throws.
2484+ core::dbus::Message::Ptr handle_open_uri(const core::dbus::Message::Ptr& in);
2485+
2486+ // We store all creation time properties;
2487+ Configuration configuration;
2488+
2489+ // Our client-facing org.mpris.MediaPlayer2.Player skeleton, just piggy-backing
2490+ // on the MPRIS-interface spec without adhering to the announcement spec that says:
2491+ //
2492+ // The media player must expose the /org/mpris/MediaPlayer2 object path, which must
2493+ // implement the following interfaces:
2494+ // - org.mpris.MediaPlayer2
2495+ // - org.mpris.MediaPlayer2.Player
2496+ mpris::Player<core::ubuntu::media::Player>::Skeleton client_skeleton;
2497+
2498+ // And we have an actual mpris-implementation owning a bus name;
2499+ struct MprisSkeleton
2500+ {
2501+ // All creation time options go here.
2502+ struct Configuration
2503+ {
2504+ // Bus connection for sending replies.
2505+ core::dbus::Bus::Ptr bus;
2506+ // Service instance to add objects to.
2507+ core::dbus::Service::Ptr service;
2508+ // Invocation handlers for all the functions we support for MPRIS.
2509+ // Please note that only a subset is covered here as we just
2510+ // error out for the rest of them
2511+ mpris::Player<mpris::MediaPlayer2>::Skeleton::Configuration::InvocationHandler
2512+ // Handles incoming next calls
2513+ handle_next,
2514+ // Handles incoming previous calls
2515+ handle_previous,
2516+ // Handles incoming pause calls
2517+ handle_pause,
2518+ // Handles incoming stop calls
2519+ handle_stop,
2520+ // Handles incoming play calls
2521+ handle_play;
2522+ };
2523+
2524+ MprisSkeleton(const Configuration& config);
2525+
2526+ Configuration configuration;
2527+ core::dbus::Object::Ptr object;
2528+ mpris::MediaPlayer2::Skeleton media_player2;
2529+ mpris::Player<mpris::MediaPlayer2>::Skeleton player;
2530+ } mpris_skeleton;
2531+
2532+ // Maps between local signals and those exposed on the bus.
2533+ struct
2534+ {
2535+ // And these are the local ones.
2536+ core::Signal<uint64_t> seeked_to;
2537+ core::Signal<void> end_of_stream;
2538+ core::Signal<media::Player::PlaybackStatus> playback_status_changed;
2539+ } signals;
2540 };
2541 }
2542 }
2543
2544=== modified file 'src/core/media/player_stub.cpp'
2545--- src/core/media/player_stub.cpp 2014-04-28 21:10:03 +0000
2546+++ src/core/media/player_stub.cpp 2014-07-07 14:32:42 +0000
2547@@ -20,6 +20,7 @@
2548 #include <core/media/track_list.h>
2549
2550 #include "codec.h"
2551+#include "player_p.h"
2552 #include "player_stub.h"
2553 #include "player_traits.h"
2554 #include "property_stub.h"
2555@@ -44,45 +45,41 @@
2556
2557 struct media::PlayerStub::Private
2558 {
2559- Private(const std::shared_ptr<Service>& parent,
2560- const std::shared_ptr<dbus::Service>& remote,
2561- const dbus::types::ObjectPath& path
2562- ) : parent(parent),
2563- texture_id(0),
2564- igbc_wrapper(nullptr),
2565- glc_wrapper(nullptr),
2566- decoding_session(decoding_service_create_session()),
2567- frame_available_cb(nullptr),
2568- frame_available_context(nullptr),
2569- path(path),
2570- object(remote->object_for_path(path)),
2571- properties
2572- {
2573- object->get_property<mpris::Player::Properties::CanPlay>(),
2574- object->get_property<mpris::Player::Properties::CanPause>(),
2575- object->get_property<mpris::Player::Properties::CanSeek>(),
2576- object->get_property<mpris::Player::Properties::CanControl>(),
2577- object->get_property<mpris::Player::Properties::CanGoNext>(),
2578- object->get_property<mpris::Player::Properties::CanGoPrevious>(),
2579- object->get_property<mpris::Player::Properties::IsVideoSource>(),
2580- object->get_property<mpris::Player::Properties::IsAudioSource>(),
2581- object->get_property<mpris::Player::Properties::PlaybackStatus>(),
2582- object->get_property<mpris::Player::Properties::LoopStatus>(),
2583- object->get_property<mpris::Player::Properties::PlaybackRate>(),
2584- object->get_property<mpris::Player::Properties::Shuffle>(),
2585- object->get_property<mpris::Player::Properties::MetaData>(),
2586- object->get_property<mpris::Player::Properties::Volume>(),
2587- object->get_property<mpris::Player::Properties::Position>(),
2588- object->get_property<mpris::Player::Properties::Duration>(),
2589- object->get_property<mpris::Player::Properties::MinimumRate>(),
2590- object->get_property<mpris::Player::Properties::MaximumRate>()
2591- },
2592- signals
2593- {
2594- object->get_signal<mpris::Player::Signals::Seeked>(),
2595- object->get_signal<mpris::Player::Signals::EndOfStream>(),
2596- object->get_signal<mpris::Player::Signals::PlaybackStatusChanged>()
2597- }
2598+ Private(const media::PlayerStub::Configuration& configuration)
2599+ : configuration(configuration),
2600+ texture_id(0),
2601+ igbc_wrapper(nullptr),
2602+ glc_wrapper(nullptr),
2603+ decoding_session(decoding_service_create_session()),
2604+ frame_available_cb(nullptr),
2605+ frame_available_context(nullptr),
2606+ properties
2607+ {
2608+ configuration.object->get_property<mpris::Player<core::ubuntu::media::Player>::Properties::CanPlay>(),
2609+ configuration.object->get_property<mpris::Player<core::ubuntu::media::Player>::Properties::CanPause>(),
2610+ configuration.object->get_property<mpris::Player<core::ubuntu::media::Player>::Properties::CanSeek>(),
2611+ configuration.object->get_property<mpris::Player<core::ubuntu::media::Player>::Properties::CanControl>(),
2612+ configuration.object->get_property<mpris::Player<core::ubuntu::media::Player>::Properties::CanGoNext>(),
2613+ configuration.object->get_property<mpris::Player<core::ubuntu::media::Player>::Properties::CanGoPrevious>(),
2614+ configuration.object->get_property<mpris::Player<core::ubuntu::media::Player>::Properties::IsVideoSource>(),
2615+ configuration.object->get_property<mpris::Player<core::ubuntu::media::Player>::Properties::IsAudioSource>(),
2616+ configuration.object->get_property<mpris::Player<core::ubuntu::media::Player>::Properties::TypedPlaybackStatus>(),
2617+ configuration.object->get_property<mpris::Player<core::ubuntu::media::Player>::Properties::TypedLoopStatus>(),
2618+ configuration.object->get_property<mpris::Player<core::ubuntu::media::Player>::Properties::PlaybackRate>(),
2619+ configuration.object->get_property<mpris::Player<core::ubuntu::media::Player>::Properties::Shuffle>(),
2620+ configuration.object->get_property<mpris::Player<core::ubuntu::media::Player>::Properties::TypedMetaData>(),
2621+ configuration.object->get_property<mpris::Player<core::ubuntu::media::Player>::Properties::Volume>(),
2622+ configuration.object->get_property<mpris::Player<core::ubuntu::media::Player>::Properties::Position>(),
2623+ configuration.object->get_property<mpris::Player<core::ubuntu::media::Player>::Properties::Duration>(),
2624+ configuration.object->get_property<mpris::Player<core::ubuntu::media::Player>::Properties::MinimumRate>(),
2625+ configuration.object->get_property<mpris::Player<core::ubuntu::media::Player>::Properties::MaximumRate>()
2626+ },
2627+ signals
2628+ {
2629+ configuration.object->get_signal<mpris::Player<core::ubuntu::media::Player>::Signals::Seeked>(),
2630+ configuration.object->get_signal<mpris::Player<core::ubuntu::media::Player>::Signals::EndOfStream>(),
2631+ configuration.object->get_signal<mpris::Player<core::ubuntu::media::Player>::Signals::PlaybackStatusChanged>()
2632+ }
2633 {
2634 }
2635
2636@@ -126,8 +123,7 @@
2637
2638 }
2639
2640- std::shared_ptr<Service> parent;
2641- std::shared_ptr<TrackList> track_list;
2642+ media::PlayerStub::Configuration configuration;
2643
2644 uint32_t texture_id;
2645 IGBCWrapperHybris igbc_wrapper;
2646@@ -138,38 +134,34 @@
2647 FrameAvailableCb frame_available_cb;
2648 void *frame_available_context;
2649
2650- dbus::Bus::Ptr bus;
2651- dbus::types::ObjectPath path;
2652- dbus::Object::Ptr object;
2653-
2654 struct
2655 {
2656- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanPlay>> can_play;
2657- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanPause>> can_pause;
2658- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanSeek>> can_seek;
2659- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanControl>> can_control;
2660- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanGoNext>> can_go_next;
2661- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanGoPrevious>> can_go_previous;
2662- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::IsVideoSource>> is_video_source;
2663- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::IsAudioSource>> is_audio_source;
2664+ std::shared_ptr<core::dbus::Property<mpris::Player<core::ubuntu::media::Player>::Properties::CanPlay>> can_play;
2665+ std::shared_ptr<core::dbus::Property<mpris::Player<core::ubuntu::media::Player>::Properties::CanPause>> can_pause;
2666+ std::shared_ptr<core::dbus::Property<mpris::Player<core::ubuntu::media::Player>::Properties::CanSeek>> can_seek;
2667+ std::shared_ptr<core::dbus::Property<mpris::Player<core::ubuntu::media::Player>::Properties::CanControl>> can_control;
2668+ std::shared_ptr<core::dbus::Property<mpris::Player<core::ubuntu::media::Player>::Properties::CanGoNext>> can_go_next;
2669+ std::shared_ptr<core::dbus::Property<mpris::Player<core::ubuntu::media::Player>::Properties::CanGoPrevious>> can_go_previous;
2670+ std::shared_ptr<core::dbus::Property<mpris::Player<core::ubuntu::media::Player>::Properties::IsVideoSource>> is_video_source;
2671+ std::shared_ptr<core::dbus::Property<mpris::Player<core::ubuntu::media::Player>::Properties::IsAudioSource>> is_audio_source;
2672
2673- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::PlaybackStatus>> playback_status;
2674- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::LoopStatus>> loop_status;
2675- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::PlaybackRate>> playback_rate;
2676- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Shuffle>> is_shuffle;
2677- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MetaData>> meta_data_for_current_track;
2678- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Volume>> volume;
2679- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Position>> position;
2680- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Duration>> duration;
2681- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MinimumRate>> minimum_playback_rate;
2682- std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MaximumRate>> maximum_playback_rate;
2683+ std::shared_ptr<core::dbus::Property<mpris::Player<core::ubuntu::media::Player>::Properties::TypedPlaybackStatus>> playback_status;
2684+ std::shared_ptr<core::dbus::Property<mpris::Player<core::ubuntu::media::Player>::Properties::TypedLoopStatus>> loop_status;
2685+ std::shared_ptr<core::dbus::Property<mpris::Player<core::ubuntu::media::Player>::Properties::PlaybackRate>> playback_rate;
2686+ std::shared_ptr<core::dbus::Property<mpris::Player<core::ubuntu::media::Player>::Properties::Shuffle>> is_shuffle;
2687+ std::shared_ptr<core::dbus::Property<mpris::Player<core::ubuntu::media::Player>::Properties::TypedMetaData>> meta_data_for_current_track;
2688+ std::shared_ptr<core::dbus::Property<mpris::Player<core::ubuntu::media::Player>::Properties::Volume>> volume;
2689+ std::shared_ptr<core::dbus::Property<mpris::Player<core::ubuntu::media::Player>::Properties::Position>> position;
2690+ std::shared_ptr<core::dbus::Property<mpris::Player<core::ubuntu::media::Player>::Properties::Duration>> duration;
2691+ std::shared_ptr<core::dbus::Property<mpris::Player<core::ubuntu::media::Player>::Properties::MinimumRate>> minimum_playback_rate;
2692+ std::shared_ptr<core::dbus::Property<mpris::Player<core::ubuntu::media::Player>::Properties::MaximumRate>> maximum_playback_rate;
2693 } properties;
2694
2695 struct Signals
2696 {
2697- typedef core::dbus::Signal<mpris::Player::Signals::Seeked, mpris::Player::Signals::Seeked::ArgumentType> DBusSeekedToSignal;
2698- typedef core::dbus::Signal<mpris::Player::Signals::EndOfStream, mpris::Player::Signals::EndOfStream::ArgumentType> DBusEndOfStreamSignal;
2699- typedef core::dbus::Signal<mpris::Player::Signals::PlaybackStatusChanged, mpris::Player::Signals::PlaybackStatusChanged::ArgumentType> DBusPlaybackStatusChangedSignal;
2700+ typedef core::dbus::Signal<mpris::Player<core::ubuntu::media::Player>::Signals::Seeked, mpris::Player<core::ubuntu::media::Player>::Signals::Seeked::ArgumentType> DBusSeekedToSignal;
2701+ typedef core::dbus::Signal<mpris::Player<core::ubuntu::media::Player>::Signals::EndOfStream, mpris::Player<core::ubuntu::media::Player>::Signals::EndOfStream::ArgumentType> DBusEndOfStreamSignal;
2702+ typedef core::dbus::Signal<mpris::Player<core::ubuntu::media::Player>::Signals::PlaybackStatusChanged, mpris::Player<core::ubuntu::media::Player>::Signals::PlaybackStatusChanged::ArgumentType> DBusPlaybackStatusChangedSignal;
2703
2704 Signals(const std::shared_ptr<DBusSeekedToSignal>& seeked,
2705 const std::shared_ptr<DBusEndOfStreamSignal>& eos,
2706@@ -228,56 +220,50 @@
2707 } signals;
2708 };
2709
2710-media::PlayerStub::PlayerStub(
2711- const std::shared_ptr<Service>& parent,
2712- const dbus::types::ObjectPath& object_path)
2713- : dbus::Stub<Player>(the_session_bus()),
2714- d(new Private{parent, access_service(), object_path})
2715+media::PlayerStub::PlayerStub(const media::PlayerStub::Configuration& config)
2716+ : d(new Private{config})
2717 {
2718- auto bus = the_session_bus();
2719- worker = std::move(std::thread([bus]()
2720- {
2721- bus->run();
2722- }));
2723 }
2724
2725 media::PlayerStub::~PlayerStub()
2726 {
2727- auto bus = the_session_bus();
2728- bus->stop();
2729-
2730- if (worker.joinable())
2731- worker.join();
2732 }
2733
2734 std::shared_ptr<media::TrackList> media::PlayerStub::track_list()
2735 {
2736- if (!d->track_list)
2737- {
2738- d->track_list = std::make_shared<media::TrackListStub>(
2739- shared_from_this(),
2740- dbus::types::ObjectPath(d->path.as_string() + "/TrackList"));
2741- }
2742- return d->track_list;
2743+ return d->configuration.track_list;
2744 }
2745
2746 media::Player::PlayerKey media::PlayerStub::key() const
2747 {
2748- auto op = d->object->invoke_method_synchronously<mpris::Player::Key, media::Player::PlayerKey>();
2749+ auto op = d->configuration.object->invoke_method_synchronously
2750+ <
2751+ mpris::Player<core::ubuntu::media::Player>::Key,
2752+ media::Player::PlayerKey
2753+ >();
2754
2755 return op.value();
2756 }
2757
2758 bool media::PlayerStub::open_uri(const media::Track::UriType& uri)
2759 {
2760- auto op = d->object->invoke_method_synchronously<mpris::Player::OpenUri, bool>(uri);
2761+ auto op = d->configuration.object->invoke_method_synchronously
2762+ <
2763+ mpris::Player<core::ubuntu::media::Player>::OpenUri,
2764+ bool
2765+ >(uri);
2766
2767 return op.value();
2768 }
2769
2770 void media::PlayerStub::create_video_sink(uint32_t texture_id)
2771 {
2772- auto op = d->object->invoke_method_synchronously<mpris::Player::CreateVideoSink, void>(texture_id);
2773+ auto op = d->configuration.object->invoke_method_synchronously
2774+ <
2775+ mpris::Player<core::ubuntu::media::Player>::CreateVideoSink,
2776+ void
2777+ >(texture_id);
2778+
2779 d->texture_id = texture_id;
2780 d->get_gl_consumer();
2781
2782@@ -292,7 +278,11 @@
2783
2784 void media::PlayerStub::next()
2785 {
2786- auto op = d->object->invoke_method_synchronously<mpris::Player::Next, void>();
2787+ auto op = d->configuration.object->invoke_method_synchronously
2788+ <
2789+ mpris::Player<core::ubuntu::media::Player>::Next,
2790+ void
2791+ >();
2792
2793 if (op.is_error())
2794 throw std::runtime_error("Problem switching to next track on remote object");
2795@@ -300,7 +290,11 @@
2796
2797 void media::PlayerStub::previous()
2798 {
2799- auto op = d->object->invoke_method_synchronously<mpris::Player::Previous, void>();
2800+ auto op = d->configuration.object->invoke_method_synchronously
2801+ <
2802+ mpris::Player<core::ubuntu::media::Player>::Previous,
2803+ void
2804+ >();
2805
2806 if (op.is_error())
2807 throw std::runtime_error("Problem switching to previous track on remote object");
2808@@ -308,7 +302,11 @@
2809
2810 void media::PlayerStub::play()
2811 {
2812- auto op = d->object->invoke_method_synchronously<mpris::Player::Play, void>();
2813+ auto op = d->configuration.object->invoke_method_synchronously
2814+ <
2815+ mpris::Player<core::ubuntu::media::Player>::Play,
2816+ void
2817+ >();
2818
2819 if (op.is_error())
2820 throw std::runtime_error("Problem starting playback on remote object");
2821@@ -316,7 +314,11 @@
2822
2823 void media::PlayerStub::pause()
2824 {
2825- auto op = d->object->invoke_method_synchronously<mpris::Player::Pause, void>();
2826+ auto op = d->configuration.object->invoke_method_synchronously
2827+ <
2828+ mpris::Player<core::ubuntu::media::Player>::Pause,
2829+ void
2830+ >();
2831
2832 if (op.is_error())
2833 throw std::runtime_error("Problem pausing playback on remote object");
2834@@ -324,7 +326,12 @@
2835
2836 void media::PlayerStub::seek_to(const std::chrono::microseconds& offset)
2837 {
2838- auto op = d->object->invoke_method_synchronously<mpris::Player::Seek, void, uint64_t>(offset.count());
2839+ auto op = d->configuration.object->invoke_method_synchronously
2840+ <
2841+ mpris::Player<core::ubuntu::media::Player>::Seek,
2842+ void,
2843+ uint64_t
2844+ >(offset.count());
2845
2846 if (op.is_error())
2847 throw std::runtime_error("Problem seeking on remote object");
2848@@ -332,7 +339,11 @@
2849
2850 void media::PlayerStub::stop()
2851 {
2852- auto op = d->object->invoke_method_synchronously<mpris::Player::Stop, void>();
2853+ auto op = d->configuration.object->invoke_method_synchronously
2854+ <
2855+ mpris::Player<core::ubuntu::media::Player>::Stop,
2856+ void
2857+ >();
2858
2859 if (op.is_error())
2860 throw std::runtime_error("Problem stopping playback on remote object");
2861
2862=== modified file 'src/core/media/player_stub.h'
2863--- src/core/media/player_stub.h 2014-04-25 17:53:00 +0000
2864+++ src/core/media/player_stub.h 2014-07-07 14:32:42 +0000
2865@@ -33,12 +33,19 @@
2866 {
2867 class Service;
2868
2869-class PlayerStub : public core::dbus::Stub<Player>
2870+class PlayerStub : public Player
2871 {
2872- public:
2873- explicit PlayerStub(
2874- const std::shared_ptr<Service>& parent,
2875- const core::dbus::types::ObjectPath& object);
2876+public:
2877+ // Creation time options being passed to c'tor go here.
2878+ struct Configuration
2879+ {
2880+ // An object instance corresponding to the remote player instance.
2881+ core::dbus::Object::Ptr object;
2882+ // TrackList instance
2883+ std::shared_ptr<TrackList> track_list;
2884+ };
2885+
2886+ explicit PlayerStub(const Configuration& configuration);
2887
2888 ~PlayerStub();
2889
2890@@ -88,7 +95,6 @@
2891 private:
2892 struct Private;
2893 std::unique_ptr<Private> d;
2894- std::thread worker;
2895 };
2896 }
2897 }
2898
2899=== modified file 'src/core/media/server/server.cpp'
2900--- src/core/media/server/server.cpp 2014-04-04 14:31:43 +0000
2901+++ src/core/media/server/server.cpp 2014-07-07 14:32:42 +0000
2902@@ -23,6 +23,7 @@
2903 #include <hybris/media/media_codec_layer.h>
2904
2905 #include "core/media/service_implementation.h"
2906+#include "core/media/the_session_bus.h"
2907
2908 #include <iostream>
2909
2910@@ -36,7 +37,14 @@
2911 decoding_service_init();
2912 cout << "Starting DecodingService..." << endl;
2913
2914- auto service = std::make_shared<media::ServiceImplementation>();
2915+
2916+ media::ServiceImplementation::Configuration config
2917+ {
2918+ media::ServiceImplementation::Configuration::dbus_app_armor_credentials_resolver_for_bus(the_session_bus()),
2919+ media::ServiceImplementation::Configuration::app_armor_permission_manager()
2920+ };
2921+
2922+ auto service = std::make_shared<media::ServiceImplementation>(config);
2923 service->run();
2924
2925 return 0;
2926
2927=== modified file 'src/core/media/service_implementation.cpp'
2928--- src/core/media/service_implementation.cpp 2014-04-23 19:00:55 +0000
2929+++ src/core/media/service_implementation.cpp 2014-07-07 14:32:42 +0000
2930@@ -20,6 +20,19 @@
2931
2932 #include "player_configuration.h"
2933 #include "player_implementation.h"
2934+#include "track_list_implementation.h"
2935+
2936+// By default, we use gstreamer as media-streaming backend
2937+#include "gstreamer/engine.h"
2938+
2939+// All the services we use
2940+#include "apparmor.h"
2941+#include "powerd_service.h"
2942+#include "unity_screen_service.h"
2943+#include "bluez/bluez.h"
2944+
2945+#include <core/dbus/dbus.h>
2946+#include <core/dbus/service.h>
2947
2948 #include <map>
2949
2950@@ -27,11 +40,61 @@
2951
2952 using namespace std;
2953
2954+namespace
2955+{
2956+core::dbus::Bus::Ptr make_bus_connection_with_executor(core::dbus::WellKnownBus bus)
2957+{
2958+ core::dbus::Bus::Ptr connection
2959+ {
2960+ new core::dbus::Bus
2961+ {
2962+ bus
2963+ }
2964+ };
2965+ connection->install_executor(core::dbus::asio::make_executor(connection));
2966+ return connection;
2967+}
2968+}
2969+
2970 struct media::ServiceImplementation::Private
2971 {
2972- Private()
2973- : key_(0)
2974- {
2975+ Private(const media::ServiceImplementation::Configuration& config)
2976+ : configuration(config),
2977+ key_{0},
2978+ session_bus{make_bus_connection_with_executor(core::dbus::WellKnownBus::session)},
2979+ session_worker{[this]() { session_bus->run(); }},
2980+ system_bus{make_bus_connection_with_executor(core::dbus::WellKnownBus::system)},
2981+ system_worker{[this]() { system_bus->run(); }},
2982+ bluez{system_bus},
2983+ powerd_stub
2984+ {
2985+ core::dbus::Service::use_service<core::Powerd>(system_bus)
2986+ },
2987+ powerd
2988+ {
2989+ powerd_stub->object_for_path(core::dbus::types::ObjectPath{"/com/canonical/powerd"})
2990+ },
2991+ screen_stub
2992+ {
2993+ core::dbus::Service::use_service<core::UScreen>(system_bus)
2994+ },
2995+ screen
2996+ {
2997+ screen_stub->object_for_path(core::dbus::types::ObjectPath{"/com/canonical/Unity/Screen"})
2998+ }
2999+ {
3000+ }
3001+ ~Private()
3002+ {
3003+ session_bus->stop();
3004+
3005+ if (session_worker.joinable())
3006+ session_worker.join();
3007+
3008+ system_bus->stop();
3009+
3010+ if (system_worker.joinable())
3011+ system_worker.join();
3012 }
3013
3014 void track_player(const std::shared_ptr<media::Player>& player)
3015@@ -69,15 +132,63 @@
3016 }
3017 }
3018
3019+ // We store all creation time options
3020+ media::ServiceImplementation::Configuration configuration;
3021 // Used for Player instance management
3022 std::map<media::Player::PlayerKey, std::shared_ptr<media::Player>> player_map;
3023+ // A simple session counter
3024 media::Player::PlayerKey key_;
3025+ // We maintain our own connection to the session bus to query other services.
3026+ core::dbus::Bus::Ptr session_bus;
3027+ // We execute our private connection to the session bus internally
3028+ std::thread session_worker;
3029+ // We have to access the system bus and run it on its own thread.
3030+ core::dbus::Bus::Ptr system_bus;
3031+ // We execute the connection to the system bus internally
3032+ std::thread system_worker;
3033+ // We maintain a bluez stub here, together with manager and media objects
3034+ struct Bluez
3035+ {
3036+ Bluez(const core::dbus::Bus::Ptr& connection)
3037+ : stub
3038+ {
3039+ core::dbus::Service::use_service<org::Bluez>(connection)
3040+ },
3041+ manager
3042+ {
3043+ stub->object_for_path(core::dbus::types::ObjectPath{"/"})
3044+ },
3045+ default_adapter
3046+ {
3047+ stub->object_for_path(
3048+ manager->transact_method
3049+ <
3050+ org::Bluez::Manager::DefaultAdapter,
3051+ core::dbus::types::ObjectPath
3052+ >().value())
3053+ }
3054+ {
3055+ }
3056+ // Accesses bluez on the bus.
3057+ core::dbus::Service::Ptr stub;
3058+ // See bluez/docs/manager-api.txt.
3059+ core::dbus::Object::Ptr manager;
3060+ // See bluez/docs/media-api.txt.
3061+ core::dbus::Object::Ptr default_adapter;
3062+ } bluez;
3063
3064+ // And we reach out to powerd/unity screen service.
3065+ // Makes sure that the device does not go to sleep while audio
3066+ // is being played back.
3067+ core::dbus::Service::Ptr powerd_stub;
3068+ core::dbus::Object::Ptr powerd;
3069+ // Makes sure that the display stays on while a video is played back.
3070+ core::dbus::Service::Ptr screen_stub;
3071+ core::dbus::Object::Ptr screen;
3072 };
3073
3074-media::ServiceImplementation::ServiceImplementation() : d(new Private())
3075+media::ServiceImplementation::ServiceImplementation(const media::ServiceImplementation::Configuration& config) : d(new Private(config))
3076 {
3077- cout << __PRETTY_FUNCTION__ << endl;
3078 }
3079
3080 media::ServiceImplementation::~ServiceImplementation()
3081@@ -87,9 +198,53 @@
3082 std::shared_ptr<media::Player> media::ServiceImplementation::create_session(
3083 const media::Player::Configuration& conf)
3084 {
3085- std::shared_ptr<media::Player> player = std::make_shared<media::PlayerImplementation>(
3086- conf.object_path, shared_from_this(), d->key());
3087+ std::shared_ptr<media::Engine> engine
3088+ {
3089+ new gstreamer::Engine()
3090+ };
3091+
3092+ media::PlayerImplementation::Configuration config
3093+ {
3094+ media::PlayerSkeleton::Configuration
3095+ {
3096+ access_bus(),
3097+ access_service()->add_object_for_path(conf.object_path),
3098+ d->configuration.resolve_incoming_msg_to_client_credentials,
3099+ d->configuration.is_client_with_credentials_allowed_to_access_uri
3100+
3101+ },
3102+ d->key(),
3103+ engine,
3104+ std::shared_ptr<media::TrackList>
3105+ {
3106+ new media::TrackListImplementation
3107+ {
3108+ media::TrackListImplementation::Configuration
3109+ {
3110+ media::TrackListSkeleton::Configuration
3111+ {
3112+ access_bus(),
3113+ access_service()->add_object_for_path(
3114+ core::dbus::types::ObjectPath
3115+ {
3116+ conf.object_path.as_string() + "/TrackList"
3117+ })
3118+ },
3119+ engine->meta_data_extractor()
3120+ }
3121+ }
3122+ },
3123+ d->system_bus,
3124+ d->bluez.stub,
3125+ d->bluez.manager,
3126+ d->bluez.default_adapter,
3127+ d->powerd,
3128+ d->screen
3129+ };
3130+
3131+ auto player = std::make_shared<media::PlayerImplementation>(config);
3132 d->track_player(player);
3133+
3134 return player;
3135 }
3136
3137@@ -97,3 +252,126 @@
3138 {
3139 d->pause_other_sessions(key);
3140 }
3141+
3142+// Returns a functor that queries the dbus daemon and apparmor to resolve
3143+// client credentials from incoming dbus messages.
3144+media::PlayerSkeleton::CredentialsResolver media::ServiceImplementation::Configuration::dbus_app_armor_credentials_resolver_for_bus(
3145+ const core::dbus::Bus::Ptr& bus)
3146+{
3147+ return [bus](const core::dbus::Message::Ptr& in) -> std::tuple<pid_t, uid_t, std::string>
3148+ {
3149+ static const auto invalid_credentials = std::make_tuple(-1, -1, std::string{"unknown"});
3150+
3151+ auto stub_service = dbus::Service::use_service<core::Apparmor>(bus);
3152+ auto apparmor_session = stub_service->object_for_path(dbus::types::ObjectPath("/org/freedesktop/DBus"));
3153+ // Get the AppArmor security context for the client
3154+ auto res_pid = apparmor_session->invoke_method_synchronously
3155+ <
3156+ core::Apparmor::GetConnectionUnixProcessID,
3157+ std::uint32_t
3158+ >(in->sender());
3159+
3160+ if (res_pid.is_error()) return invalid_credentials;
3161+
3162+ auto res_uid = apparmor_session->invoke_method_synchronously
3163+ <
3164+ core::Apparmor::GetConnectionUnixUser,
3165+ std::uint32_t
3166+ >(in->sender());
3167+
3168+ if (res_uid.is_error()) return invalid_credentials;
3169+
3170+ auto res_context = apparmor_session->invoke_method_synchronously
3171+ <
3172+ core::Apparmor::GetConnectionAppArmorSecurityContext,
3173+ std::string
3174+ >(in->sender());
3175+
3176+ if (res_context.is_error()) return invalid_credentials;
3177+
3178+ return std::make_tuple(
3179+ pid_t{static_cast<pid_t>(res_pid.value())},
3180+ uid_t{static_cast<uid_t>(res_uid.value())},
3181+ res_context.value());
3182+ };
3183+}
3184+
3185+// Returns a functor that analyzes the app armor confinement profile of the client,
3186+// queries a whitelist for unconfined apps and makes sure that a URI requested to
3187+// be opened is accessible by the client.
3188+media::PlayerSkeleton::PermissionManager media::ServiceImplementation::Configuration::app_armor_permission_manager()
3189+{
3190+ return [](const std::tuple<pid_t, uid_t, std::string>& credentials, const std::string& uri)
3191+ {
3192+ const auto& context = std::get<2>(credentials);
3193+
3194+ if (context.empty() || uri.empty())
3195+ {
3196+ std::cout << "Client denied access since context or uri are empty" << std::endl;
3197+ return false;
3198+ }
3199+
3200+ if (context == "unconfined")
3201+ {
3202+ std::cout << "Client allowed access since it's unconfined" << std::endl;
3203+ return true;
3204+ }
3205+
3206+ size_t pos = context.find_first_of('_');
3207+ if (pos == std::string::npos)
3208+ {
3209+ std::cout << "Client denied access since it's an invalid apparmor security context" << std::endl;
3210+ return false;
3211+ }
3212+
3213+ const std::string pkgname = context.substr(0, pos);
3214+ std::cout << "client pkgname: " << pkgname << std::endl;
3215+ std::cout << "uri: " << uri << std::endl;
3216+
3217+ // All confined apps can access their own files
3218+ if (uri.find(std::string(".local/share/" + pkgname + "/")) != std::string::npos
3219+ || uri.find(std::string(".cache/" + pkgname + "/")) != std::string::npos)
3220+ {
3221+ std::cout << "Client can access content in ~/.local/share/" << pkgname << " or ~/.cache/" << pkgname << std::endl;
3222+ return true;
3223+ }
3224+ else if (uri.find(std::string("opt/click.ubuntu.com/")) != std::string::npos
3225+ && uri.find(pkgname) != std::string::npos)
3226+ {
3227+ std::cout << "Client can access content in own opt directory" << std::endl;
3228+ return true;
3229+ }
3230+ else if ((uri.find(std::string("/system/media/audio/ui/")) != std::string::npos
3231+ || uri.find(std::string("/android/system/media/audio/ui/")) != std::string::npos)
3232+ && pkgname == "com.ubuntu.camera")
3233+ {
3234+ std::cout << "Camera app can access ui sounds" << std::endl;
3235+ return true;
3236+ }
3237+ // TODO: Check if the trust store previously allowed direct access to uri
3238+
3239+ // Check in ~/Music and ~/Videos
3240+ // TODO: when the trust store lands, check it to see if this app can access the dirs and
3241+ // then remove the explicit whitelist of the music-app, and gallery-app
3242+ else if ((pkgname == "com.ubuntu.music" || pkgname == "com.ubuntu.gallery") &&
3243+ (uri.find(std::string("Music/")) != std::string::npos
3244+ || uri.find(std::string("Videos/")) != std::string::npos))
3245+ {
3246+ std::cout << "Client can access content in ~/Music or ~/Videos" << std::endl;
3247+ return true;
3248+ }
3249+ else if (uri.find(std::string("http://")) != std::string::npos
3250+ || uri.find(std::string("rtsp://")) != std::string::npos)
3251+ {
3252+ std::cout << "Client can access streaming content" << std::endl;
3253+ return true;
3254+ }
3255+ else
3256+ {
3257+ std::cout << "Client denied access to open_uri()" << std::endl;
3258+ return false;
3259+ }
3260+
3261+ return false;
3262+ };
3263+}
3264
3265=== modified file 'src/core/media/service_implementation.h'
3266--- src/core/media/service_implementation.h 2014-04-23 19:00:55 +0000
3267+++ src/core/media/service_implementation.h 2014-07-07 14:32:42 +0000
3268@@ -21,6 +21,8 @@
3269
3270 #include "service_skeleton.h"
3271
3272+#include "player_skeleton.h"
3273+
3274 namespace core
3275 {
3276 namespace ubuntu
3277@@ -32,15 +34,33 @@
3278
3279 class ServiceImplementation : public ServiceSkeleton
3280 {
3281- public:
3282- ServiceImplementation ();
3283+public:
3284+ // All creation-time properties go here.
3285+ struct Configuration
3286+ {
3287+ // Returns a functor that queries the dbus daemon and apparmor to resolve
3288+ // client credentials from incoming dbus messages.
3289+ static PlayerSkeleton::CredentialsResolver dbus_app_armor_credentials_resolver_for_bus(const core::dbus::Bus::Ptr& connection);
3290+
3291+ // Returns a functor that analyzes the app armor confinement profile of the client,
3292+ // queries a whitelist for unconfined apps and makes sure that a URI requested to
3293+ // be opened is accessible by the client.
3294+ static PlayerSkeleton::PermissionManager app_armor_permission_manager();
3295+
3296+ // The functor called by the skeleton to resolve credentials.
3297+ PlayerSkeleton::CredentialsResolver resolve_incoming_msg_to_client_credentials;
3298+ // The functor called by the skeleton to verify if a client is allowed to access a uri.
3299+ PlayerSkeleton::PermissionManager is_client_with_credentials_allowed_to_access_uri;
3300+ };
3301+
3302+ ServiceImplementation (const Configuration& config);
3303 ~ServiceImplementation ();
3304
3305 std::shared_ptr<Player> create_session(const Player::Configuration&);
3306
3307 void pause_other_sessions(Player::PlayerKey key);
3308
3309- private:
3310+private:
3311 struct Private;
3312 std::shared_ptr<Private> d;
3313 };
3314
3315=== modified file 'src/core/media/service_skeleton.cpp'
3316--- src/core/media/service_skeleton.cpp 2014-04-23 19:00:55 +0000
3317+++ src/core/media/service_skeleton.cpp 2014-07-07 14:32:42 +0000
3318@@ -20,6 +20,7 @@
3319
3320 #include "mpris/service.h"
3321 #include "player_configuration.h"
3322+#include "player_p.h"
3323 #include "the_session_bus.h"
3324
3325 #include <core/dbus/message.h>
3326@@ -56,6 +57,10 @@
3327 std::placeholders::_1));
3328 }
3329
3330+ ~Private()
3331+ {
3332+ }
3333+
3334 void handle_create_session(const core::dbus::Message::Ptr& msg)
3335 {
3336 static unsigned int session_counter = 0;
3337@@ -104,7 +109,6 @@
3338
3339 media::ServiceSkeleton* impl;
3340 dbus::Object::Ptr object;
3341-
3342 };
3343
3344 media::ServiceSkeleton::ServiceSkeleton()
3345
3346=== modified file 'src/core/media/service_stub.cpp'
3347--- src/core/media/service_stub.cpp 2014-04-23 19:00:55 +0000
3348+++ src/core/media/service_stub.cpp 2014-07-07 14:32:42 +0000
3349@@ -20,6 +20,8 @@
3350 #include "service_traits.h"
3351
3352 #include "player_stub.h"
3353+#include "track_list_stub.h"
3354+
3355 #include "the_session_bus.h"
3356
3357 #include "mpris/service.h"
3358@@ -27,41 +29,72 @@
3359 namespace dbus = core::dbus;
3360 namespace media = core::ubuntu::media;
3361
3362-struct media::ServiceStub::Private
3363-{
3364- dbus::Object::Ptr object;
3365-};
3366-
3367 media::ServiceStub::ServiceStub()
3368 : core::dbus::Stub<media::Service>(the_session_bus()),
3369- d(new Private{
3370- access_service()->object_for_path(
3371- dbus::types::ObjectPath(
3372- dbus::traits::Service<media::Service>::object_path()))})
3373+ object
3374+ {
3375+ access_service()->object_for_path(dbus::types::ObjectPath
3376+ {
3377+ dbus::traits::Service<media::Service>::object_path()
3378+ })
3379+ },
3380+ worker
3381+ {
3382+ []() { the_session_bus()->run(); }
3383+ }
3384 {
3385 }
3386
3387 media::ServiceStub::~ServiceStub()
3388 {
3389+ the_session_bus()->stop();
3390+
3391+ if (worker.joinable())
3392+ worker.join();
3393 }
3394
3395 std::shared_ptr<media::Player> media::ServiceStub::create_session(const media::Player::Configuration&)
3396 {
3397- auto op = d->object->invoke_method_synchronously<mpris::Service::CreateSession,
3398+ auto op = object->invoke_method_synchronously<mpris::Service::CreateSession,
3399 dbus::types::ObjectPath>();
3400
3401- if (op.is_error())
3402- throw std::runtime_error("Problem creating session: " + op.error());
3403-
3404- return std::shared_ptr<media::Player>(new media::PlayerStub(shared_from_this(), op.value()));
3405+ if (op.is_error()) throw std::runtime_error
3406+ {
3407+ "Problem creating session: " + op.error()
3408+ };
3409+
3410+ media::PlayerStub::Configuration config
3411+ {
3412+ access_service()->object_for_path(op.value()),
3413+ std::shared_ptr<media::TrackList>
3414+ {
3415+ new media::TrackListStub
3416+ {
3417+ media::TrackListStub::Configuration
3418+ {
3419+ access_service()->object_for_path(core::dbus::types::ObjectPath
3420+ {
3421+ op.value().as_string() + "/TrackList"
3422+ })
3423+ }
3424+ }
3425+ }
3426+ };
3427+
3428+ return std::shared_ptr<media::Player>(new media::PlayerStub(config));
3429 }
3430
3431 void media::ServiceStub::pause_other_sessions(media::Player::PlayerKey key)
3432 {
3433 std::cout << __PRETTY_FUNCTION__ << std::endl;
3434- auto op = d->object->invoke_method_synchronously<mpris::Service::PauseOtherSessions,
3435- void>(key);
3436+ auto op = object->invoke_method_synchronously
3437+ <
3438+ mpris::Service::PauseOtherSessions,
3439+ void
3440+ >(key);
3441
3442- if (op.is_error())
3443- throw std::runtime_error("Problem pausing other sessions: " + op.error());
3444+ if (op.is_error()) throw std::runtime_error
3445+ {
3446+ "Problem pausing other sessions: " + op.error()
3447+ };
3448 }
3449
3450=== modified file 'src/core/media/service_stub.h'
3451--- src/core/media/service_stub.h 2014-04-23 19:00:55 +0000
3452+++ src/core/media/service_stub.h 2014-07-07 14:32:42 +0000
3453@@ -23,6 +23,7 @@
3454
3455 #include "service_traits.h"
3456
3457+#include <core/dbus/object.h>
3458 #include <core/dbus/stub.h>
3459
3460 #include <memory>
3461@@ -35,16 +36,16 @@
3462 {
3463 class ServiceStub : public core::dbus::Stub<core::ubuntu::media::Service>
3464 {
3465- public:
3466+public:
3467 ServiceStub();
3468 ~ServiceStub();
3469
3470 std::shared_ptr<Player> create_session(const Player::Configuration&);
3471 void pause_other_sessions(Player::PlayerKey key);
3472
3473- private:
3474- struct Private;
3475- std::unique_ptr<Private> d;
3476+private:
3477+ core::dbus::Object::Ptr object;
3478+ std::thread worker;
3479 };
3480 }
3481 }
3482
3483=== modified file 'src/core/media/track_list_implementation.cpp'
3484--- src/core/media/track_list_implementation.cpp 2014-03-25 14:57:15 +0000
3485+++ src/core/media/track_list_implementation.cpp 2014-07-07 14:32:42 +0000
3486@@ -30,16 +30,13 @@
3487 {
3488 typedef std::map<Track::Id, std::tuple<Track::UriType, Track::MetaData>> MetaDataCache;
3489
3490- dbus::types::ObjectPath path;
3491+ media::TrackListImplementation::Configuration configuration;
3492 MetaDataCache meta_data_cache;
3493- std::shared_ptr<media::Engine::MetaDataExtractor> extractor;
3494 };
3495
3496-media::TrackListImplementation::TrackListImplementation(
3497- const dbus::types::ObjectPath& op,
3498- const std::shared_ptr<media::Engine::MetaDataExtractor>& extractor)
3499- : media::TrackListSkeleton(op),
3500- d(new Private{op, Private::MetaDataCache{}, extractor})
3501+media::TrackListImplementation::TrackListImplementation(const media::TrackListImplementation::Configuration& config)
3502+ : media::TrackListSkeleton(config.skeleton_configuration),
3503+ d(new Private{config, Private::MetaDataCache{}})
3504 {
3505 can_edit_tracks().set(true);
3506 }
3507@@ -75,7 +72,7 @@
3508 {
3509 static size_t track_counter = 0;
3510
3511- std::stringstream ss; ss << d->path.as_string() << "/" << track_counter++;
3512+ std::stringstream ss; ss << d->configuration.skeleton_configuration.object->path().as_string() << "/" << track_counter++;
3513 Track::Id id{ss.str()};
3514
3515 auto result = tracks().update([this, id, position, make_current](TrackList::Container& container)
3516@@ -91,7 +88,7 @@
3517 {
3518 d->meta_data_cache[id] = std::make_tuple(
3519 uri,
3520- d->extractor->meta_data_for_track_with_uri(uri));
3521+ d->configuration.extractor->meta_data_for_track_with_uri(uri));
3522 } else
3523 {
3524 std::get<0>(d->meta_data_cache[id]) = uri;
3525
3526=== modified file 'src/core/media/track_list_implementation.h'
3527--- src/core/media/track_list_implementation.h 2014-03-25 14:57:15 +0000
3528+++ src/core/media/track_list_implementation.h 2014-07-07 14:32:42 +0000
3529@@ -31,9 +31,16 @@
3530 class TrackListImplementation : public TrackListSkeleton
3531 {
3532 public:
3533- TrackListImplementation(
3534- const core::dbus::types::ObjectPath& op,
3535- const std::shared_ptr<Engine::MetaDataExtractor>& extractor);
3536+ // All creation time options go here.
3537+ struct Configuration
3538+ {
3539+ // All creation options for the skeleton.
3540+ TrackListSkeleton::Configuration skeleton_configuration;
3541+ // The meta-data implementation that should be used.
3542+ std::shared_ptr<Engine::MetaDataExtractor> extractor;
3543+ };
3544+
3545+ TrackListImplementation(const Configuration& config);
3546 ~TrackListImplementation();
3547
3548 Track::UriType query_uri_for_track(const Track::Id& id);
3549
3550=== modified file 'src/core/media/track_list_skeleton.cpp'
3551--- src/core/media/track_list_skeleton.cpp 2014-03-25 14:57:15 +0000
3552+++ src/core/media/track_list_skeleton.cpp 2014-07-07 14:32:42 +0000
3553@@ -42,12 +42,12 @@
3554
3555 struct media::TrackListSkeleton::Private
3556 {
3557- Private(media::TrackListSkeleton* impl,
3558- dbus::Object::Ptr object)
3559- : impl(impl),
3560- object(object),
3561- can_edit_tracks(object->get_property<mpris::TrackList::Properties::CanEditTracks>()),
3562- tracks(object->get_property<mpris::TrackList::Properties::Tracks>()),
3563+ Private(const media::TrackListSkeleton::Configuration& configuration,
3564+ media::TrackListSkeleton* impl)
3565+ : configuration(configuration),
3566+ impl(impl),
3567+ can_edit_tracks(configuration.object->get_property<mpris::TrackList::Properties::CanEditTracks>()),
3568+ tracks(configuration.object->get_property<mpris::TrackList::Properties::Tracks>()),
3569 current_track(tracks->get().begin()),
3570 empty_iterator(tracks->get().begin())
3571 {
3572@@ -62,7 +62,7 @@
3573
3574 auto reply = dbus::Message::make_method_return(msg);
3575 reply->writer() << *meta_data;
3576- impl->access_bus()->send(reply);
3577+ configuration.bus->send(reply);
3578 }
3579
3580 void handle_add_track_with_uri_at(const core::dbus::Message::Ptr& msg)
3581@@ -73,7 +73,7 @@
3582 impl->add_track_with_uri_at(uri, after, make_current);
3583
3584 auto reply = dbus::Message::make_method_return(msg);
3585- impl->access_bus()->send(reply);
3586+ configuration.bus->send(reply);
3587 }
3588
3589 void handle_remove_track(const core::dbus::Message::Ptr& msg)
3590@@ -84,7 +84,7 @@
3591 impl->remove_track(track);
3592
3593 auto reply = dbus::Message::make_method_return(msg);
3594- impl->access_bus()->send(reply);
3595+ configuration.bus->send(reply);
3596 }
3597
3598 void handle_go_to(const core::dbus::Message::Ptr& msg)
3599@@ -95,11 +95,11 @@
3600 impl->go_to(track);
3601
3602 auto reply = dbus::Message::make_method_return(msg);
3603- impl->access_bus()->send(reply);
3604+ configuration.bus->send(reply);
3605 }
3606
3607+ media::TrackListSkeleton::Configuration configuration;
3608 media::TrackListSkeleton* impl;
3609- dbus::Object::Ptr object;
3610
3611 std::shared_ptr<core::dbus::Property<mpris::TrackList::Properties::CanEditTracks>> can_edit_tracks;
3612 std::shared_ptr<core::dbus::Property<mpris::TrackList::Properties::Tracks>> tracks;
3613@@ -112,27 +112,25 @@
3614 core::Signal<Track::Id> on_track_changed;
3615 };
3616
3617-media::TrackListSkeleton::TrackListSkeleton(
3618- const dbus::types::ObjectPath& op)
3619- : dbus::Skeleton<media::TrackList>(the_session_bus()),
3620- d(new Private(this, access_service()->add_object_for_path(op)))
3621+media::TrackListSkeleton::TrackListSkeleton(const media::TrackListSkeleton::Configuration& config)
3622+ : d(new Private(config, this))
3623 {
3624- d->object->install_method_handler<mpris::TrackList::GetTracksMetadata>(
3625+ d->configuration.object->install_method_handler<mpris::TrackList::GetTracksMetadata>(
3626 std::bind(&Private::handle_get_tracks_metadata,
3627 std::ref(d),
3628 std::placeholders::_1));
3629
3630- d->object->install_method_handler<mpris::TrackList::AddTrack>(
3631+ d->configuration.object->install_method_handler<mpris::TrackList::AddTrack>(
3632 std::bind(&Private::handle_add_track_with_uri_at,
3633 std::ref(d),
3634 std::placeholders::_1));
3635
3636- d->object->install_method_handler<mpris::TrackList::RemoveTrack>(
3637+ d->configuration.object->install_method_handler<mpris::TrackList::RemoveTrack>(
3638 std::bind(&Private::handle_remove_track,
3639 std::ref(d),
3640 std::placeholders::_1));
3641
3642- d->object->install_method_handler<mpris::TrackList::GoTo>(
3643+ d->configuration.object->install_method_handler<mpris::TrackList::GoTo>(
3644 std::bind(&Private::handle_go_to,
3645 std::ref(d),
3646 std::placeholders::_1));
3647
3648=== modified file 'src/core/media/track_list_skeleton.h'
3649--- src/core/media/track_list_skeleton.h 2014-03-25 14:57:15 +0000
3650+++ src/core/media/track_list_skeleton.h 2014-07-07 14:32:42 +0000
3651@@ -22,6 +22,7 @@
3652
3653 #include <core/media/player.h>
3654
3655+#include <core/dbus/object.h>
3656 #include <core/dbus/skeleton.h>
3657
3658 namespace core
3659@@ -30,11 +31,18 @@
3660 {
3661 namespace media
3662 {
3663-class TrackListSkeleton : public core::dbus::Skeleton<core::ubuntu::media::TrackList>
3664+class TrackListSkeleton : public core::ubuntu::media::TrackList
3665 {
3666 public:
3667- TrackListSkeleton(
3668- const core::dbus::types::ObjectPath& op);
3669+ struct Configuration
3670+ {
3671+ // Bus connection for replying to incoming calls.
3672+ core::dbus::Bus::Ptr bus;
3673+ // The dbus object representing the tracklist instance.
3674+ core::dbus::Object::Ptr object;
3675+ };
3676+
3677+ TrackListSkeleton(const Configuration& configuration);
3678 ~TrackListSkeleton();
3679
3680 bool has_next() const;
3681
3682=== modified file 'src/core/media/track_list_stub.cpp'
3683--- src/core/media/track_list_stub.cpp 2014-02-12 15:53:57 +0000
3684+++ src/core/media/track_list_stub.cpp 2014-07-07 14:32:42 +0000
3685@@ -25,8 +25,6 @@
3686 #include "track_list_traits.h"
3687 #include "the_session_bus.h"
3688
3689-#include "mpris/track_list.h"
3690-
3691 #include <core/dbus/property.h>
3692 #include <core/dbus/types/object_path.h>
3693 #include <core/dbus/types/variant.h>
3694@@ -38,61 +36,33 @@
3695 namespace dbus = core::dbus;
3696 namespace media = core::ubuntu::media;
3697
3698-struct media::TrackListStub::Private
3699-{
3700- Private(
3701- TrackListStub* impl,
3702- const std::shared_ptr<media::Player>& parent,
3703- const dbus::types::ObjectPath& op)
3704- : impl(impl),
3705- parent(parent),
3706- object(impl->access_service()->object_for_path(op)),
3707- can_edit_tracks(object->get_property<mpris::TrackList::Properties::CanEditTracks>()),
3708- tracks(object->get_property<mpris::TrackList::Properties::Tracks>())
3709- {
3710- }
3711-
3712- TrackListStub* impl;
3713- std::shared_ptr<media::Player> parent;
3714- dbus::Object::Ptr object;
3715-
3716- std::shared_ptr<core::dbus::Property<mpris::TrackList::Properties::CanEditTracks>> can_edit_tracks;
3717- std::shared_ptr<core::dbus::Property<mpris::TrackList::Properties::Tracks>> tracks;
3718-
3719- core::Signal<void> on_track_list_replaced;
3720- core::Signal<Track::Id> on_track_added;
3721- core::Signal<Track::Id> on_track_removed;
3722- core::Signal<Track::Id> on_track_changed;
3723-};
3724-
3725-media::TrackListStub::TrackListStub(
3726- const std::shared_ptr<media::Player>& parent,
3727- const core::dbus::types::ObjectPath& op)
3728- : dbus::Stub<media::TrackList>(the_session_bus()),
3729- d(new Private(this, parent, op))
3730-{
3731-}
3732-
3733-media::TrackListStub::~TrackListStub()
3734+media::TrackListStub::TrackListStub(const media::TrackListStub::Configuration& config)
3735+ : configuration(config),
3736+ properties
3737+ {
3738+ configuration.object->get_property<mpris::TrackList::Properties::CanEditTracks>(),
3739+ configuration.object->get_property<mpris::TrackList::Properties::Tracks>()
3740+ }
3741 {
3742 }
3743
3744 const core::Property<bool>& media::TrackListStub::can_edit_tracks() const
3745 {
3746- return *d->can_edit_tracks;
3747+ return *properties.can_edit_tracks;
3748 }
3749
3750 const core::Property<media::TrackList::Container>& media::TrackListStub::tracks() const
3751 {
3752- return *d->tracks;
3753+ return *properties.tracks;
3754 }
3755
3756 media::Track::MetaData media::TrackListStub::query_meta_data_for_track(const media::Track::Id& id)
3757 {
3758- auto op
3759- = d->object->invoke_method_synchronously<
3760+ auto op = configuration.object->invoke_method_synchronously
3761+ <
3762 mpris::TrackList::GetTracksMetadata,
3763- std::map<std::string, std::string>>(id);
3764+ std::map<std::string, std::string>
3765+ >(id);
3766
3767 if (op.is_error())
3768 throw std::runtime_error("Problem querying meta data for track: " + op.error());
3769@@ -110,10 +80,11 @@
3770 const media::Track::Id& id,
3771 bool make_current)
3772 {
3773- auto op = d->object->invoke_method_synchronously<mpris::TrackList::AddTrack, void>(
3774- uri,
3775- id,
3776- make_current);
3777+ auto op = configuration.object->invoke_method_synchronously
3778+ <
3779+ mpris::TrackList::AddTrack,
3780+ void
3781+ >(uri, id, make_current);
3782
3783 if (op.is_error())
3784 throw std::runtime_error("Problem adding track: " + op.error());
3785@@ -121,8 +92,11 @@
3786
3787 void media::TrackListStub::remove_track(const media::Track::Id& track)
3788 {
3789- auto op = d->object->invoke_method_synchronously<mpris::TrackList::RemoveTrack, void>(
3790- track);
3791+ auto op = configuration.object->invoke_method_synchronously
3792+ <
3793+ mpris::TrackList::RemoveTrack,
3794+ void
3795+ >(track);
3796
3797 if (op.is_error())
3798 throw std::runtime_error("Problem removing track: " + op.error());
3799@@ -130,8 +104,11 @@
3800
3801 void media::TrackListStub::go_to(const media::Track::Id& track)
3802 {
3803- auto op = d->object->invoke_method_synchronously<mpris::TrackList::GoTo, void>(
3804- track);
3805+ auto op = configuration.object->invoke_method_synchronously
3806+ <
3807+ mpris::TrackList::GoTo,
3808+ void
3809+ >(track);
3810
3811 if (op.is_error())
3812 throw std::runtime_error("Problem adding track: " + op.error());
3813@@ -139,20 +116,20 @@
3814
3815 const core::Signal<void>& media::TrackListStub::on_track_list_replaced() const
3816 {
3817- return d->on_track_list_replaced;
3818+ return signals.on_track_list_replaced;
3819 }
3820
3821 const core::Signal<media::Track::Id>& media::TrackListStub::on_track_added() const
3822 {
3823- return d->on_track_added;
3824+ return signals.on_track_added;
3825 }
3826
3827 const core::Signal<media::Track::Id>& media::TrackListStub::on_track_removed() const
3828 {
3829- return d->on_track_removed;
3830+ return signals.on_track_removed;
3831 }
3832
3833 const core::Signal<media::Track::Id>& media::TrackListStub::on_track_changed() const
3834 {
3835- return d->on_track_changed;
3836+ return signals.on_track_changed;
3837 }
3838
3839=== modified file 'src/core/media/track_list_stub.h'
3840--- src/core/media/track_list_stub.h 2014-02-12 15:53:57 +0000
3841+++ src/core/media/track_list_stub.h 2014-07-07 14:32:42 +0000
3842@@ -21,6 +21,7 @@
3843
3844 #include <core/media/track_list.h>
3845
3846+#include "mpris/track_list.h"
3847 #include "track_list_traits.h"
3848
3849 #include <core/dbus/stub.h>
3850@@ -33,14 +34,21 @@
3851 {
3852 namespace media
3853 {
3854-class TrackListStub : public core::dbus::Stub<core::ubuntu::media::TrackList>
3855+class TrackListStub : public core::ubuntu::media::TrackList
3856 {
3857 public:
3858- TrackListStub(
3859- const std::shared_ptr<Player>& parent,
3860- const core::dbus::types::ObjectPath& op);
3861- ~TrackListStub();
3862-
3863+ // Creation time options passed to c'tors go here.
3864+ struct Configuration
3865+ {
3866+ // The remote tracklist instance.
3867+ core::dbus::Object::Ptr object;
3868+ };
3869+
3870+ // Creates a new stub instance, setting up local endpoints for communicating
3871+ // with the remote track list instance.
3872+ TrackListStub(const Configuration& config);
3873+
3874+ // from core::ubuntu::media::Player
3875 const core::Property<bool>& can_edit_tracks() const;
3876 const core::Property<Container>& tracks() const;
3877
3878@@ -57,8 +65,24 @@
3879 const core::Signal<Track::Id>& on_track_changed() const;
3880
3881 private:
3882- struct Private;
3883- std::unique_ptr<Private> d;
3884+ // We store all options passed at creation time.
3885+ media::TrackListStub::Configuration configuration;
3886+
3887+ // Stubs for access remote properties.
3888+ struct
3889+ {
3890+ std::shared_ptr<core::dbus::Property<mpris::TrackList::Properties::CanEditTracks>> can_edit_tracks;
3891+ std::shared_ptr<core::dbus::Property<mpris::TrackList::Properties::Tracks>> tracks;
3892+ } properties;
3893+
3894+ // And the signals notifying us of changes.
3895+ struct
3896+ {
3897+ core::Signal<void> on_track_list_replaced;
3898+ core::Signal<Track::Id> on_track_added;
3899+ core::Signal<Track::Id> on_track_removed;
3900+ core::Signal<Track::Id> on_track_changed;
3901+ } signals;
3902 };
3903 }
3904 }
3905
3906=== modified file 'tests/acceptance-tests/service.cpp'
3907--- tests/acceptance-tests/service.cpp 2014-04-04 14:31:43 +0000
3908+++ tests/acceptance-tests/service.cpp 2014-07-07 14:32:42 +0000
3909@@ -26,6 +26,8 @@
3910
3911 #include "test_data.h"
3912
3913+#include <core/dbus/asio/executor.h>
3914+
3915 #include <core/testing/cross_process_sync.h>
3916 #include <core/testing/fork_and_run.h>
3917
3918@@ -78,7 +80,19 @@
3919 {
3920 SigTermCatcher sc;
3921
3922- auto service = std::make_shared<media::ServiceImplementation>();
3923+ core::dbus::Bus::Ptr session_bus
3924+ {
3925+ new core::dbus::Bus(core::dbus::WellKnownBus::session)
3926+ };
3927+ session_bus->install_executor(core::dbus::asio::make_executor(session_bus));
3928+
3929+ media::ServiceImplementation::Configuration config
3930+ {
3931+ media::ServiceImplementation::Configuration::dbus_app_armor_credentials_resolver_for_bus(session_bus),
3932+ media::ServiceImplementation::Configuration::app_armor_permission_manager()
3933+ };
3934+
3935+ auto service = std::make_shared<media::ServiceImplementation>(config);
3936 std::thread t([&service](){service->run();});
3937
3938 sync_service_start.try_signal_ready_for(std::chrono::milliseconds{500});
3939@@ -120,7 +134,19 @@
3940 {
3941 SigTermCatcher sc;
3942
3943- auto service = std::make_shared<media::ServiceImplementation>();
3944+ core::dbus::Bus::Ptr session_bus
3945+ {
3946+ new core::dbus::Bus(core::dbus::WellKnownBus::session)
3947+ };
3948+ session_bus->install_executor(core::dbus::asio::make_executor(session_bus));
3949+
3950+ media::ServiceImplementation::Configuration config
3951+ {
3952+ media::ServiceImplementation::Configuration::dbus_app_armor_credentials_resolver_for_bus(session_bus),
3953+ media::ServiceImplementation::Configuration::app_armor_permission_manager()
3954+ };
3955+
3956+ auto service = std::make_shared<media::ServiceImplementation>(config);
3957 std::thread t([&service](){service->run();});
3958
3959 sync_service_start.try_signal_ready_for(std::chrono::milliseconds{500});
3960@@ -173,7 +199,19 @@
3961 {
3962 SigTermCatcher sc;
3963
3964- auto service = std::make_shared<media::ServiceImplementation>();
3965+ core::dbus::Bus::Ptr session_bus
3966+ {
3967+ new core::dbus::Bus(core::dbus::WellKnownBus::session)
3968+ };
3969+ session_bus->install_executor(core::dbus::asio::make_executor(session_bus));
3970+
3971+ media::ServiceImplementation::Configuration config
3972+ {
3973+ media::ServiceImplementation::Configuration::dbus_app_armor_credentials_resolver_for_bus(session_bus),
3974+ media::ServiceImplementation::Configuration::app_armor_permission_manager()
3975+ };
3976+
3977+ auto service = std::make_shared<media::ServiceImplementation>(config);
3978 std::thread t([&service](){service->run();});
3979
3980 sync_service_start.try_signal_ready_for(std::chrono::milliseconds{500});
3981@@ -252,7 +290,19 @@
3982 {
3983 SigTermCatcher sc;
3984
3985- auto service = std::make_shared<media::ServiceImplementation>();
3986+ core::dbus::Bus::Ptr session_bus
3987+ {
3988+ new core::dbus::Bus(core::dbus::WellKnownBus::session)
3989+ };
3990+ session_bus->install_executor(core::dbus::asio::make_executor(session_bus));
3991+
3992+ media::ServiceImplementation::Configuration config
3993+ {
3994+ media::ServiceImplementation::Configuration::dbus_app_armor_credentials_resolver_for_bus(session_bus),
3995+ media::ServiceImplementation::Configuration::app_armor_permission_manager()
3996+ };
3997+
3998+ auto service = std::make_shared<media::ServiceImplementation>(config);
3999 std::thread t([&service](){service->run();});
4000
4001 sync_service_start.try_signal_ready_for(std::chrono::milliseconds{500});
4002@@ -311,7 +361,19 @@
4003 {
4004 SigTermCatcher sc;
4005
4006- auto service = std::make_shared<media::ServiceImplementation>();
4007+ core::dbus::Bus::Ptr session_bus
4008+ {
4009+ new core::dbus::Bus(core::dbus::WellKnownBus::session)
4010+ };
4011+ session_bus->install_executor(core::dbus::asio::make_executor(session_bus));
4012+
4013+ media::ServiceImplementation::Configuration config
4014+ {
4015+ media::ServiceImplementation::Configuration::dbus_app_armor_credentials_resolver_for_bus(session_bus),
4016+ media::ServiceImplementation::Configuration::app_armor_permission_manager()
4017+ };
4018+
4019+ auto service = std::make_shared<media::ServiceImplementation>(config);
4020 std::thread t([&service](){service->run();});
4021
4022 sync_service_start.try_signal_ready_for(std::chrono::milliseconds{500});

Subscribers

People subscribed via source and target branches