Music Hub  ..
A session-wide music playback service
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
player_skeleton.cpp
Go to the documentation of this file.
1 /*
2  * Copyright © 2013-2014 Canonical Ltd.
3  *
4  * This program is free software: you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License version 3,
6  * as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  *
16  * Authored by: Thomas Voß <thomas.voss@canonical.com>
17  */
18 
19 #include "apparmor.h"
20 #include "codec.h"
21 #include "player_skeleton.h"
22 #include "player_traits.h"
23 #include "property_stub.h"
24 #include "the_session_bus.h"
25 
26 #include "mpris/player.h"
27 
28 #include <core/dbus/object.h>
29 #include <core/dbus/property.h>
30 #include <core/dbus/stub.h>
31 #include <core/dbus/asio/executor.h>
32 
33 namespace dbus = core::dbus;
34 namespace media = core::ubuntu::media;
35 
37 {
38  Private(media::PlayerSkeleton* player, const dbus::types::ObjectPath& session)
39  : impl(player),
40  object(impl->access_service()->add_object_for_path(session)),
41  apparmor_session(nullptr),
43  {
44  object->get_property<mpris::Player::Properties::CanPlay>(),
45  object->get_property<mpris::Player::Properties::CanPause>(),
46  object->get_property<mpris::Player::Properties::CanSeek>(),
47  object->get_property<mpris::Player::Properties::CanControl>(),
48  object->get_property<mpris::Player::Properties::CanGoNext>(),
49  object->get_property<mpris::Player::Properties::CanGoPrevious>(),
50  object->get_property<mpris::Player::Properties::IsVideoSource>(),
51  object->get_property<mpris::Player::Properties::IsAudioSource>(),
52  object->get_property<mpris::Player::Properties::PlaybackStatus>(),
53  object->get_property<mpris::Player::Properties::LoopStatus>(),
54  object->get_property<mpris::Player::Properties::PlaybackRate>(),
55  object->get_property<mpris::Player::Properties::Shuffle>(),
56  object->get_property<mpris::Player::Properties::MetaData>(),
57  object->get_property<mpris::Player::Properties::Volume>(),
58  object->get_property<mpris::Player::Properties::Position>(),
59  object->get_property<mpris::Player::Properties::Duration>(),
60  object->get_property<mpris::Player::Properties::MinimumRate>(),
61  object->get_property<mpris::Player::Properties::MaximumRate>()
62  },
63  signals
64  {
65  object->get_signal<mpris::Player::Signals::Seeked>(),
66  object->get_signal<mpris::Player::Signals::EndOfStream>(),
67  object->get_signal<mpris::Player::Signals::PlaybackStatusChanged>()
68  }
69  {
70  }
71 
72  void handle_next(const core::dbus::Message::Ptr& msg)
73  {
74  impl->next();
75  auto reply = dbus::Message::make_method_return(msg);
76  impl->access_bus()->send(reply);
77  }
78 
79  void handle_previous(const core::dbus::Message::Ptr& msg)
80  {
81  impl->previous();
82  auto reply = dbus::Message::make_method_return(msg);
83  impl->access_bus()->send(reply);
84  }
85 
86  void handle_pause(const core::dbus::Message::Ptr& msg)
87  {
88  impl->pause();
89  auto reply = dbus::Message::make_method_return(msg);
90  impl->access_bus()->send(reply);
91  }
92 
93  void handle_playpause(DBusMessage*)
94  {
95  }
96 
97  void handle_stop(const core::dbus::Message::Ptr& msg)
98  {
99  impl->stop();
100  auto reply = dbus::Message::make_method_return(msg);
101  impl->access_bus()->send(reply);
102  }
103 
104  void handle_play(const core::dbus::Message::Ptr& msg)
105  {
106  impl->play();
107  auto reply = dbus::Message::make_method_return(msg);
108  impl->access_bus()->send(reply);
109  }
110 
111  void handle_seek(const core::dbus::Message::Ptr& in)
112  {
113  uint64_t ticks;
114  in->reader() >> ticks;
115  impl->seek_to(std::chrono::microseconds(ticks));
116 
117  auto reply = dbus::Message::make_method_return(in);
118  impl->access_bus()->send(reply);
119  }
120 
121  void handle_set_position(const core::dbus::Message::Ptr&)
122  {
123  }
124 
125  void handle_create_video_sink(const core::dbus::Message::Ptr& in)
126  {
127  uint32_t texture_id;
128  in->reader() >> texture_id;
129  impl->create_video_sink(texture_id);
130 
131  auto reply = dbus::Message::make_method_return(in);
132  impl->access_bus()->send(reply);
133  }
134 
135  std::string get_client_apparmor_context(const core::dbus::Message::Ptr& msg)
136  {
137  auto bus = std::shared_ptr<dbus::Bus>(new dbus::Bus(core::dbus::WellKnownBus::session));
138  bus->install_executor(dbus::asio::make_executor(bus));
139 
140  auto stub_service = dbus::Service::use_service(bus, dbus::traits::Service<core::Apparmor>::interface_name());
141  apparmor_session = stub_service->object_for_path(dbus::types::ObjectPath("/org/freedesktop/DBus"));
142  // Get the AppArmor security context for the client
143  auto result = apparmor_session->invoke_method_synchronously<core::Apparmor::getConnectionAppArmorSecurityContext, std::string>(msg->sender());
144  if (result.is_error())
145  {
146  std::cout << "Error getting apparmor profile: " << result.error().print() << std::endl;
147  return std::string();
148  }
149 
150  return result.value();
151  }
152 
153  bool does_client_have_access(const std::string& context, const std::string& uri)
154  {
155  if (context.empty() || uri.empty())
156  {
157  std::cout << "Client denied access since context or uri are empty" << std::endl;
158  return false;
159  }
160 
161  if (context == "unconfined")
162  {
163  std::cout << "Client allowed access since it's unconfined" << std::endl;
164  return true;
165  }
166 
167  size_t pos = context.find_first_of('_');
168  if (pos == std::string::npos)
169  {
170  std::cout << "Client denied access since it's an invalid apparmor security context" << std::endl;
171  return false;
172  }
173 
174  const std::string pkgname = context.substr(0, pos);
175  std::cout << "client pkgname: " << pkgname << std::endl;
176  std::cout << "uri: " << uri << std::endl;
177 
178  // All confined apps can access their own files
179  if (uri.find(std::string(".local/share/" + pkgname + "/")) != std::string::npos
180  || uri.find(std::string(".cache/" + pkgname + "/")) != std::string::npos)
181  {
182  std::cout << "Client can access content in ~/.local/share/" << pkgname << " or ~/.cache/" << pkgname << std::endl;
183  return true;
184  }
185  else if (uri.find(std::string("opt/click.ubuntu.com/")) != std::string::npos
186  && uri.find(pkgname) != std::string::npos)
187  {
188  std::cout << "Client can access content in own opt directory" << std::endl;
189  return true;
190  }
191  else if ((uri.find(std::string("/system/media/audio/ui/")) != std::string::npos
192  || uri.find(std::string("/android/system/media/audio/ui/")) != std::string::npos)
193  && pkgname == "com.ubuntu.camera")
194  {
195  std::cout << "Camera app can access ui sounds" << std::endl;
196  return true;
197  }
198  // TODO: Check if the trust store previously allowed direct access to uri
199 
200  // Check in ~/Music and ~/Videos
201  // TODO: when the trust store lands, check it to see if this app can access the dirs and
202  // then remove the explicit whitelist of the music-app
203  else if (pkgname == "com.ubuntu.music" &&
204  (uri.find(std::string("Music/")) != std::string::npos
205  || uri.find(std::string("Videos/")) != std::string::npos))
206  {
207  std::cout << "Client can access content in ~/Music or ~/Videos" << std::endl;
208  return true;
209  }
210  else if (uri.find(std::string("http://")) != std::string::npos
211  || uri.find(std::string("rtsp://")) != std::string::npos)
212  {
213  std::cout << "Client can access streaming content" << std::endl;
214  return true;
215  }
216  else
217  {
218  std::cout << "Client denied access to open_uri()" << std::endl;
219  return false;
220  }
221  }
222 
223  void handle_key(const core::dbus::Message::Ptr& in)
224  {
225  auto reply = dbus::Message::make_method_return(in);
226  reply->writer() << impl->key();
227  impl->access_bus()->send(reply);
228  }
229 
230  void handle_open_uri(const core::dbus::Message::Ptr& in)
231  {
232  Track::UriType uri;
233  in->reader() >> uri;
234 
235  std::string context = get_client_apparmor_context(in);
236  bool have_access = does_client_have_access(context, uri);
237 
238  auto reply = dbus::Message::make_method_return(in);
239  if (have_access)
240  reply->writer() << impl->open_uri(uri);
241  else
242  reply->writer() << false;
243  impl->access_bus()->send(reply);
244  }
245 
247  dbus::Object::Ptr object;
248  dbus::Object::Ptr apparmor_session;
249  struct
250  {
251  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanPlay>> can_play;
252  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanPause>> can_pause;
253  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanSeek>> can_seek;
254  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanControl>> can_control;
255  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanGoNext>> can_go_next;
256  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanGoPrevious>> can_go_previous;
257  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::IsVideoSource>> is_video_source;
258  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::IsAudioSource>> is_audio_source;
259 
260  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::PlaybackStatus>> playback_status;
261  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::LoopStatus>> loop_status;
262  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::PlaybackRate>> playback_rate;
263  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Shuffle>> is_shuffle;
264  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MetaData>> meta_data_for_current_track;
265  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Volume>> volume;
266  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Position>> position;
267  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Duration>> duration;
268  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MinimumRate>> minimum_playback_rate;
269  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MaximumRate>> maximum_playback_rate;
270  } properties;
271 
272  struct Signals
273  {
274  typedef core::dbus::Signal<mpris::Player::Signals::Seeked, mpris::Player::Signals::Seeked::ArgumentType> DBusSeekedToSignal;
275  typedef core::dbus::Signal<mpris::Player::Signals::EndOfStream, mpris::Player::Signals::EndOfStream::ArgumentType> DBusEndOfStreamSignal;
276  typedef core::dbus::Signal<mpris::Player::Signals::PlaybackStatusChanged, mpris::Player::Signals::PlaybackStatusChanged::ArgumentType> DBusPlaybackStatusChangedSignal;
277 
278  Signals(const std::shared_ptr<DBusSeekedToSignal>& seeked,
279  const std::shared_ptr<DBusEndOfStreamSignal>& eos,
280  const std::shared_ptr<DBusPlaybackStatusChangedSignal>& status)
281  : dbus
282  {
283  seeked,
284  eos,
285  status
286  },
287  seeked_to(),
288  end_of_stream(),
290  {
291  seeked_to.connect([this](std::uint64_t value)
292  {
293  dbus.seeked_to->emit(value);
294  });
295 
296  end_of_stream.connect([this]()
297  {
298  dbus.end_of_stream->emit();
299  });
300 
301  playback_status_changed.connect([this](const media::Player::PlaybackStatus& status)
302  {
303  dbus.playback_status_changed->emit(status);
304  });
305  }
306 
307  struct DBus
308  {
309  std::shared_ptr<DBusSeekedToSignal> seeked_to;
310  std::shared_ptr<DBusEndOfStreamSignal> end_of_stream;
311  std::shared_ptr<DBusPlaybackStatusChangedSignal> playback_status_changed;
312  } dbus;
313  core::Signal<uint64_t> seeked_to;
314  core::Signal<void> end_of_stream;
315  core::Signal<media::Player::PlaybackStatus> playback_status_changed;
316  } signals;
317 
318 };
319 
321  const core::dbus::types::ObjectPath& session_path)
322  : dbus::Skeleton<media::Player>(the_session_bus()),
323  d(new Private{this, session_path})
324 {
325  d->object->install_method_handler<mpris::Player::Next>(
326  std::bind(&Private::handle_next,
327  std::ref(d),
328  std::placeholders::_1));
329  d->object->install_method_handler<mpris::Player::Previous>(
330  std::bind(&Private::handle_previous,
331  std::ref(d),
332  std::placeholders::_1));
333  d->object->install_method_handler<mpris::Player::Pause>(
334  std::bind(&Private::handle_pause,
335  std::ref(d),
336  std::placeholders::_1));
337  d->object->install_method_handler<mpris::Player::Stop>(
338  std::bind(&Private::handle_stop,
339  std::ref(d),
340  std::placeholders::_1));
341  d->object->install_method_handler<mpris::Player::Play>(
342  std::bind(&Private::handle_play,
343  std::ref(d),
344  std::placeholders::_1));
345  d->object->install_method_handler<mpris::Player::Seek>(
346  std::bind(&Private::handle_seek,
347  std::ref(d),
348  std::placeholders::_1));
349  d->object->install_method_handler<mpris::Player::SetPosition>(
350  std::bind(&Private::handle_set_position,
351  std::ref(d),
352  std::placeholders::_1));
353  d->object->install_method_handler<mpris::Player::CreateVideoSink>(
355  std::ref(d),
356  std::placeholders::_1));
357  d->object->install_method_handler<mpris::Player::Key>(
358  std::bind(&Private::handle_key,
359  std::ref(d),
360  std::placeholders::_1));
361  d->object->install_method_handler<mpris::Player::OpenUri>(
362  std::bind(&Private::handle_open_uri,
363  std::ref(d),
364  std::placeholders::_1));
365 }
366 
368 {
369 }
370 
371 const core::Property<bool>& media::PlayerSkeleton::can_play() const
372 {
373  return *d->properties.can_play;
374 }
375 
376 const core::Property<bool>& media::PlayerSkeleton::can_pause() const
377 {
378  return *d->properties.can_pause;
379 }
380 
381 const core::Property<bool>& media::PlayerSkeleton::can_seek() const
382 {
383  return *d->properties.can_seek;
384 }
385 
386 const core::Property<bool>& media::PlayerSkeleton::can_go_previous() const
387 {
388  return *d->properties.can_go_previous;
389 }
390 
391 const core::Property<bool>& media::PlayerSkeleton::can_go_next() const
392 {
393  return *d->properties.can_go_next;
394 }
395 
396 const core::Property<bool>& media::PlayerSkeleton::is_video_source() const
397 {
398  return *d->properties.is_video_source;
399 }
400 
401 const core::Property<bool>& media::PlayerSkeleton::is_audio_source() const
402 {
403  return *d->properties.is_audio_source;
404 }
405 
406 const core::Property<media::Player::PlaybackStatus>& media::PlayerSkeleton::playback_status() const
407 {
408  return *d->properties.playback_status;
409 }
410 
411 const core::Property<media::Player::LoopStatus>& media::PlayerSkeleton::loop_status() const
412 {
413  return *d->properties.loop_status;
414 }
415 
416 const core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::playback_rate() const
417 {
418  return *d->properties.playback_rate;
419 }
420 
421 const core::Property<bool>& media::PlayerSkeleton::is_shuffle() const
422 {
423  return *d->properties.is_shuffle;
424 }
425 
426 const core::Property<media::Track::MetaData>& media::PlayerSkeleton::meta_data_for_current_track() const
427 {
428  return *d->properties.meta_data_for_current_track;
429 }
430 
431 const core::Property<media::Player::Volume>& media::PlayerSkeleton::volume() const
432 {
433  return *d->properties.volume;
434 }
435 
436 const core::Property<uint64_t>& media::PlayerSkeleton::position() const
437 {
438  return *d->properties.position;
439 }
440 
441 const core::Property<uint64_t>& media::PlayerSkeleton::duration() const
442 {
443  return *d->properties.duration;
444 }
445 
446 const core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::minimum_playback_rate() const
447 {
448  return *d->properties.minimum_playback_rate;
449 }
450 
451 const core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::maximum_playback_rate() const
452 {
453  return *d->properties.maximum_playback_rate;
454 }
455 
456 core::Property<media::Player::LoopStatus>& media::PlayerSkeleton::loop_status()
457 {
458  return *d->properties.loop_status;
459 }
460 
461 core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::playback_rate()
462 {
463  return *d->properties.playback_rate;
464 }
465 
466 core::Property<bool>& media::PlayerSkeleton::is_shuffle()
467 {
468  return *d->properties.is_shuffle;
469 }
470 
471 core::Property<media::Player::Volume>& media::PlayerSkeleton::volume()
472 {
473  return *d->properties.volume;
474 }
475 
476 core::Property<uint64_t>& media::PlayerSkeleton::position()
477 {
478  return *d->properties.position;
479 }
480 
481 core::Property<uint64_t>& media::PlayerSkeleton::duration()
482 {
483  return *d->properties.duration;
484 }
485 
486 core::Property<media::Player::PlaybackStatus>& media::PlayerSkeleton::playback_status()
487 {
488  return *d->properties.playback_status;
489 }
490 
491 core::Property<bool>& media::PlayerSkeleton::can_play()
492 {
493  return *d->properties.can_play;
494 }
495 
496 core::Property<bool>& media::PlayerSkeleton::can_pause()
497 {
498  return *d->properties.can_pause;
499 }
500 
501 core::Property<bool>& media::PlayerSkeleton::can_seek()
502 {
503  return *d->properties.can_seek;
504 }
505 
506 core::Property<bool>& media::PlayerSkeleton::can_go_previous()
507 {
508  return *d->properties.can_go_previous;
509 }
510 
511 core::Property<bool>& media::PlayerSkeleton::can_go_next()
512 {
513  return *d->properties.can_go_next;
514 }
515 
516 core::Property<bool>& media::PlayerSkeleton::is_video_source()
517 {
518  return *d->properties.is_video_source;
519 }
520 
521 core::Property<bool>& media::PlayerSkeleton::is_audio_source()
522 {
523  return *d->properties.is_audio_source;
524 }
525 
526 
527 core::Property<media::Track::MetaData>& media::PlayerSkeleton::meta_data_for_current_track()
528 {
529  return *d->properties.meta_data_for_current_track;
530 }
531 
532 core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::minimum_playback_rate()
533 {
534  return *d->properties.minimum_playback_rate;
535 }
536 
537 core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::maximum_playback_rate()
538 {
539  return *d->properties.maximum_playback_rate;
540 }
541 
542 const core::Signal<uint64_t>& media::PlayerSkeleton::seeked_to() const
543 {
544  return d->signals.seeked_to;
545 }
546 
547 core::Signal<uint64_t>& media::PlayerSkeleton::seeked_to()
548 {
549  return d->signals.seeked_to;
550 }
551 
552 const core::Signal<void>& media::PlayerSkeleton::end_of_stream() const
553 {
554  return d->signals.end_of_stream;
555 }
556 
557 core::Signal<void>& media::PlayerSkeleton::end_of_stream()
558 {
559  return d->signals.end_of_stream;
560 }
561 
562 core::Signal<media::Player::PlaybackStatus>& media::PlayerSkeleton::playback_status_changed()
563 {
564  return d->signals.playback_status_changed;
565 }
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::CanPause > > can_pause
void handle_previous(const core::dbus::Message::Ptr &msg)
std::shared_ptr< DBusSeekedToSignal > seeked_to
Signals(const std::shared_ptr< DBusSeekedToSignal > &seeked, const std::shared_ptr< DBusEndOfStreamSignal > &eos, const std::shared_ptr< DBusPlaybackStatusChangedSignal > &status)
void handle_play(const core::dbus::Message::Ptr &msg)
virtual const core::Property< PlaybackStatus > & playback_status() const
virtual const core::Property< bool > & is_video_source() const
void handle_playpause(DBusMessage *)
virtual const core::Signal< void > & end_of_stream() const
virtual const core::Property< bool > & can_seek() const
virtual const core::Property< PlaybackRate > & maximum_playback_rate() const
core::dbus::Bus::Ptr the_session_bus()
virtual const core::Property< bool > & is_shuffle() const
virtual const core::Property< bool > & can_go_next() const
virtual const core::Property< bool > & can_go_previous() const
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::Volume > > volume
virtual const core::Property< uint64_t > & duration() const
void handle_set_position(const core::dbus::Message::Ptr &)
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::MinimumRate > > minimum_playback_rate
bool does_client_have_access(const std::string &context, const std::string &uri)
std::shared_ptr< DBusEndOfStreamSignal > end_of_stream
virtual const core::Property< bool > & can_play() const
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::Duration > > duration
virtual const core::Signal< uint64_t > & seeked_to() const
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::CanGoNext > > can_go_next
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::CanPlay > > can_play
virtual const core::Property< Track::MetaData > & meta_data_for_current_track() const
std::shared_ptr< DBusPlaybackStatusChangedSignal > playback_status_changed
virtual const core::Property< bool > & can_pause() const
virtual const core::Property< LoopStatus > & loop_status() const
void handle_stop(const core::dbus::Message::Ptr &msg)
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::CanControl > > can_control
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::MaximumRate > > maximum_playback_rate
struct media::PlayerSkeleton::Private::Signals::DBus dbus
virtual const core::Property< PlaybackRate > & playback_rate() const
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::LoopStatus > > loop_status
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::Shuffle > > is_shuffle
core::dbus::Signal< mpris::Player::Signals::EndOfStream, mpris::Player::Signals::EndOfStream::ArgumentType > DBusEndOfStreamSignal
media::PlayerSkeleton * impl
PlayerSkeleton(const core::dbus::types::ObjectPath &session_path)
void handle_pause(const core::dbus::Message::Ptr &msg)
core::dbus::Signal< mpris::Player::Signals::PlaybackStatusChanged, mpris::Player::Signals::PlaybackStatusChanged::ArgumentType > DBusPlaybackStatusChangedSignal
Private(media::PlayerSkeleton *player, const dbus::types::ObjectPath &session)
virtual const core::Property< PlaybackRate > & minimum_playback_rate() const
struct media::PlayerSkeleton::Private::Signals signals
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::IsVideoSource > > is_video_source
void handle_seek(const core::dbus::Message::Ptr &in)
void handle_open_uri(const core::dbus::Message::Ptr &in)
virtual const core::Property< Volume > & volume() const
std::string UriType
Definition: track.h:40
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::PlaybackStatus > > playback_status
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::Position > > position
void handle_next(const core::dbus::Message::Ptr &msg)
virtual core::Signal< PlaybackStatus > & playback_status_changed()
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::IsAudioSource > > is_audio_source
virtual const core::Property< bool > & is_audio_source() const
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::PlaybackRate > > playback_rate
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::CanGoPrevious > > can_go_previous
core::dbus::Signal< mpris::Player::Signals::Seeked, mpris::Player::Signals::Seeked::ArgumentType > DBusSeekedToSignal
core::Signal< media::Player::PlaybackStatus > playback_status_changed
struct media::PlayerSkeleton::Private::@12 properties
virtual const core::Property< uint64_t > & position() const
void handle_create_video_sink(const core::dbus::Message::Ptr &in)
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::CanSeek > > can_seek
void handle_key(const core::dbus::Message::Ptr &in)
std::string get_client_apparmor_context(const core::dbus::Message::Ptr &msg)
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::MetaData > > meta_data_for_current_track