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, and gallery-app
203  else if ((pkgname == "com.ubuntu.music" || pkgname == "com.ubuntu.gallery") &&
204  (uri.find(std::string("Music/")) != std::string::npos
205  || uri.find(std::string("Videos/")) != std::string::npos
206  || uri.find(std::string("/media")) != std::string::npos))
207  {
208  std::cout << "Client can access content in ~/Music or ~/Videos" << std::endl;
209  return true;
210  }
211  else if (uri.find(std::string("http://")) != std::string::npos
212  || uri.find(std::string("rtsp://")) != std::string::npos)
213  {
214  std::cout << "Client can access streaming content" << std::endl;
215  return true;
216  }
217  else
218  {
219  std::cout << "Client denied access to open_uri()" << std::endl;
220  return false;
221  }
222  }
223 
224  void handle_key(const core::dbus::Message::Ptr& in)
225  {
226  auto reply = dbus::Message::make_method_return(in);
227  reply->writer() << impl->key();
228  impl->access_bus()->send(reply);
229  }
230 
231  void handle_open_uri(const core::dbus::Message::Ptr& in)
232  {
233  Track::UriType uri;
234  in->reader() >> uri;
235 
236  std::string context = get_client_apparmor_context(in);
237  bool have_access = does_client_have_access(context, uri);
238 
239  auto reply = dbus::Message::make_method_return(in);
240  if (have_access)
241  reply->writer() << impl->open_uri(uri);
242  else
243  reply->writer() << false;
244  impl->access_bus()->send(reply);
245  }
246 
248  dbus::Object::Ptr object;
249  dbus::Object::Ptr apparmor_session;
250  struct
251  {
252  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanPlay>> can_play;
253  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanPause>> can_pause;
254  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanSeek>> can_seek;
255  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanControl>> can_control;
256  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanGoNext>> can_go_next;
257  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanGoPrevious>> can_go_previous;
258  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::IsVideoSource>> is_video_source;
259  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::IsAudioSource>> is_audio_source;
260 
261  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::PlaybackStatus>> playback_status;
262  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::LoopStatus>> loop_status;
263  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::PlaybackRate>> playback_rate;
264  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Shuffle>> is_shuffle;
265  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MetaData>> meta_data_for_current_track;
266  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Volume>> volume;
267  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Position>> position;
268  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Duration>> duration;
269  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MinimumRate>> minimum_playback_rate;
270  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MaximumRate>> maximum_playback_rate;
271  } properties;
272 
273  struct Signals
274  {
275  typedef core::dbus::Signal<mpris::Player::Signals::Seeked, mpris::Player::Signals::Seeked::ArgumentType> DBusSeekedToSignal;
276  typedef core::dbus::Signal<mpris::Player::Signals::EndOfStream, mpris::Player::Signals::EndOfStream::ArgumentType> DBusEndOfStreamSignal;
277  typedef core::dbus::Signal<mpris::Player::Signals::PlaybackStatusChanged, mpris::Player::Signals::PlaybackStatusChanged::ArgumentType> DBusPlaybackStatusChangedSignal;
278 
279  Signals(const std::shared_ptr<DBusSeekedToSignal>& seeked,
280  const std::shared_ptr<DBusEndOfStreamSignal>& eos,
281  const std::shared_ptr<DBusPlaybackStatusChangedSignal>& status)
282  : dbus
283  {
284  seeked,
285  eos,
286  status
287  },
288  seeked_to(),
289  end_of_stream(),
291  {
292  seeked_to.connect([this](std::uint64_t value)
293  {
294  dbus.seeked_to->emit(value);
295  });
296 
297  end_of_stream.connect([this]()
298  {
299  dbus.end_of_stream->emit();
300  });
301 
302  playback_status_changed.connect([this](const media::Player::PlaybackStatus& status)
303  {
304  dbus.playback_status_changed->emit(status);
305  });
306  }
307 
308  struct DBus
309  {
310  std::shared_ptr<DBusSeekedToSignal> seeked_to;
311  std::shared_ptr<DBusEndOfStreamSignal> end_of_stream;
312  std::shared_ptr<DBusPlaybackStatusChangedSignal> playback_status_changed;
313  } dbus;
314  core::Signal<uint64_t> seeked_to;
315  core::Signal<void> end_of_stream;
316  core::Signal<media::Player::PlaybackStatus> playback_status_changed;
317  } signals;
318 
319 };
320 
322  const core::dbus::types::ObjectPath& session_path)
323  : dbus::Skeleton<media::Player>(the_session_bus()),
324  d(new Private{this, session_path})
325 {
326  d->object->install_method_handler<mpris::Player::Next>(
327  std::bind(&Private::handle_next,
328  std::ref(d),
329  std::placeholders::_1));
330  d->object->install_method_handler<mpris::Player::Previous>(
331  std::bind(&Private::handle_previous,
332  std::ref(d),
333  std::placeholders::_1));
334  d->object->install_method_handler<mpris::Player::Pause>(
335  std::bind(&Private::handle_pause,
336  std::ref(d),
337  std::placeholders::_1));
338  d->object->install_method_handler<mpris::Player::Stop>(
339  std::bind(&Private::handle_stop,
340  std::ref(d),
341  std::placeholders::_1));
342  d->object->install_method_handler<mpris::Player::Play>(
343  std::bind(&Private::handle_play,
344  std::ref(d),
345  std::placeholders::_1));
346  d->object->install_method_handler<mpris::Player::Seek>(
347  std::bind(&Private::handle_seek,
348  std::ref(d),
349  std::placeholders::_1));
350  d->object->install_method_handler<mpris::Player::SetPosition>(
351  std::bind(&Private::handle_set_position,
352  std::ref(d),
353  std::placeholders::_1));
354  d->object->install_method_handler<mpris::Player::CreateVideoSink>(
356  std::ref(d),
357  std::placeholders::_1));
358  d->object->install_method_handler<mpris::Player::Key>(
359  std::bind(&Private::handle_key,
360  std::ref(d),
361  std::placeholders::_1));
362  d->object->install_method_handler<mpris::Player::OpenUri>(
363  std::bind(&Private::handle_open_uri,
364  std::ref(d),
365  std::placeholders::_1));
366 }
367 
369 {
370 }
371 
372 const core::Property<bool>& media::PlayerSkeleton::can_play() const
373 {
374  return *d->properties.can_play;
375 }
376 
377 const core::Property<bool>& media::PlayerSkeleton::can_pause() const
378 {
379  return *d->properties.can_pause;
380 }
381 
382 const core::Property<bool>& media::PlayerSkeleton::can_seek() const
383 {
384  return *d->properties.can_seek;
385 }
386 
387 const core::Property<bool>& media::PlayerSkeleton::can_go_previous() const
388 {
389  return *d->properties.can_go_previous;
390 }
391 
392 const core::Property<bool>& media::PlayerSkeleton::can_go_next() const
393 {
394  return *d->properties.can_go_next;
395 }
396 
397 const core::Property<bool>& media::PlayerSkeleton::is_video_source() const
398 {
399  return *d->properties.is_video_source;
400 }
401 
402 const core::Property<bool>& media::PlayerSkeleton::is_audio_source() const
403 {
404  return *d->properties.is_audio_source;
405 }
406 
407 const core::Property<media::Player::PlaybackStatus>& media::PlayerSkeleton::playback_status() const
408 {
409  return *d->properties.playback_status;
410 }
411 
412 const core::Property<media::Player::LoopStatus>& media::PlayerSkeleton::loop_status() const
413 {
414  return *d->properties.loop_status;
415 }
416 
417 const core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::playback_rate() const
418 {
419  return *d->properties.playback_rate;
420 }
421 
422 const core::Property<bool>& media::PlayerSkeleton::is_shuffle() const
423 {
424  return *d->properties.is_shuffle;
425 }
426 
427 const core::Property<media::Track::MetaData>& media::PlayerSkeleton::meta_data_for_current_track() const
428 {
429  return *d->properties.meta_data_for_current_track;
430 }
431 
432 const core::Property<media::Player::Volume>& media::PlayerSkeleton::volume() const
433 {
434  return *d->properties.volume;
435 }
436 
437 const core::Property<uint64_t>& media::PlayerSkeleton::position() const
438 {
439  return *d->properties.position;
440 }
441 
442 const core::Property<uint64_t>& media::PlayerSkeleton::duration() const
443 {
444  return *d->properties.duration;
445 }
446 
447 const core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::minimum_playback_rate() const
448 {
449  return *d->properties.minimum_playback_rate;
450 }
451 
452 const core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::maximum_playback_rate() const
453 {
454  return *d->properties.maximum_playback_rate;
455 }
456 
457 core::Property<media::Player::LoopStatus>& media::PlayerSkeleton::loop_status()
458 {
459  return *d->properties.loop_status;
460 }
461 
462 core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::playback_rate()
463 {
464  return *d->properties.playback_rate;
465 }
466 
467 core::Property<bool>& media::PlayerSkeleton::is_shuffle()
468 {
469  return *d->properties.is_shuffle;
470 }
471 
472 core::Property<media::Player::Volume>& media::PlayerSkeleton::volume()
473 {
474  return *d->properties.volume;
475 }
476 
477 core::Property<uint64_t>& media::PlayerSkeleton::position()
478 {
479  return *d->properties.position;
480 }
481 
482 core::Property<uint64_t>& media::PlayerSkeleton::duration()
483 {
484  return *d->properties.duration;
485 }
486 
487 core::Property<media::Player::PlaybackStatus>& media::PlayerSkeleton::playback_status()
488 {
489  return *d->properties.playback_status;
490 }
491 
492 core::Property<bool>& media::PlayerSkeleton::can_play()
493 {
494  return *d->properties.can_play;
495 }
496 
497 core::Property<bool>& media::PlayerSkeleton::can_pause()
498 {
499  return *d->properties.can_pause;
500 }
501 
502 core::Property<bool>& media::PlayerSkeleton::can_seek()
503 {
504  return *d->properties.can_seek;
505 }
506 
507 core::Property<bool>& media::PlayerSkeleton::can_go_previous()
508 {
509  return *d->properties.can_go_previous;
510 }
511 
512 core::Property<bool>& media::PlayerSkeleton::can_go_next()
513 {
514  return *d->properties.can_go_next;
515 }
516 
517 core::Property<bool>& media::PlayerSkeleton::is_video_source()
518 {
519  return *d->properties.is_video_source;
520 }
521 
522 core::Property<bool>& media::PlayerSkeleton::is_audio_source()
523 {
524  return *d->properties.is_audio_source;
525 }
526 
527 
528 core::Property<media::Track::MetaData>& media::PlayerSkeleton::meta_data_for_current_track()
529 {
530  return *d->properties.meta_data_for_current_track;
531 }
532 
533 core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::minimum_playback_rate()
534 {
535  return *d->properties.minimum_playback_rate;
536 }
537 
538 core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::maximum_playback_rate()
539 {
540  return *d->properties.maximum_playback_rate;
541 }
542 
543 const core::Signal<uint64_t>& media::PlayerSkeleton::seeked_to() const
544 {
545  return d->signals.seeked_to;
546 }
547 
548 core::Signal<uint64_t>& media::PlayerSkeleton::seeked_to()
549 {
550  return d->signals.seeked_to;
551 }
552 
553 const core::Signal<void>& media::PlayerSkeleton::end_of_stream() const
554 {
555  return d->signals.end_of_stream;
556 }
557 
558 core::Signal<void>& media::PlayerSkeleton::end_of_stream()
559 {
560  return d->signals.end_of_stream;
561 }
562 
563 core::Signal<media::Player::PlaybackStatus>& media::PlayerSkeleton::playback_status_changed()
564 {
565  return d->signals.playback_status_changed;
566 }
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