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  * Jim Hodapp <jim.hodapp@canonical.com>
18  */
19 
20 #include "apparmor.h"
21 #include "codec.h"
22 #include "player_skeleton.h"
23 #include "player_traits.h"
24 #include "property_stub.h"
25 #include "the_session_bus.h"
26 #include "xesam.h"
27 
28 #include "mpris/media_player2.h"
29 #include "mpris/metadata.h"
30 #include "mpris/player.h"
31 #include "mpris/playlists.h"
32 
33 #include <core/dbus/object.h>
34 #include <core/dbus/property.h>
35 #include <core/dbus/stub.h>
36 
37 #include <core/dbus/asio/executor.h>
38 #include <core/dbus/interfaces/properties.h>
39 
40 namespace dbus = core::dbus;
41 namespace media = core::ubuntu::media;
42 
44 {
46  const std::string& identity,
47  const std::shared_ptr<core::dbus::Bus>& bus,
48  const std::shared_ptr<core::dbus::Object>& session)
49  : impl(player),
50  identity(identity),
51  bus(bus),
52  object(session),
53  apparmor_session(nullptr),
54  dbus_stub{bus},
56  signals
57  {
62  }
63  {
64  }
65 
66  void handle_next(const core::dbus::Message::Ptr& msg)
67  {
68  impl->next();
69  auto reply = dbus::Message::make_method_return(msg);
70  bus->send(reply);
71  }
72 
73  void handle_previous(const core::dbus::Message::Ptr& msg)
74  {
75  impl->previous();
76  auto reply = dbus::Message::make_method_return(msg);
77  bus->send(reply);
78  }
79 
80  void handle_pause(const core::dbus::Message::Ptr& msg)
81  {
82  impl->pause();
83  auto reply = dbus::Message::make_method_return(msg);
84  bus->send(reply);
85  }
86 
87  void handle_stop(const core::dbus::Message::Ptr& msg)
88  {
89  impl->stop();
90  auto reply = dbus::Message::make_method_return(msg);
91  bus->send(reply);
92  }
93 
94  void handle_play(const core::dbus::Message::Ptr& msg)
95  {
96  impl->play();
97  auto reply = dbus::Message::make_method_return(msg);
98  bus->send(reply);
99  }
100 
101  void handle_play_pause(const core::dbus::Message::Ptr& msg)
102  {
103  switch(impl->playback_status().get())
104  {
105  case core::ubuntu::media::Player::PlaybackStatus::ready:
106  case core::ubuntu::media::Player::PlaybackStatus::paused:
107  case core::ubuntu::media::Player::PlaybackStatus::stopped:
108  impl->play();
109  break;
110  case core::ubuntu::media::Player::PlaybackStatus::playing:
111  impl->pause();
112  break;
113  default:
114  break;
115  }
116 
117  bus->send(dbus::Message::make_method_return(msg));
118  }
119 
120  void handle_seek(const core::dbus::Message::Ptr& in)
121  {
122  uint64_t ticks;
123  in->reader() >> ticks;
124  impl->seek_to(std::chrono::microseconds(ticks));
125 
126  auto reply = dbus::Message::make_method_return(in);
127  bus->send(reply);
128  }
129 
130  void handle_set_position(const core::dbus::Message::Ptr&)
131  {
132  }
133 
134  void handle_create_video_sink(const core::dbus::Message::Ptr& in)
135  {
136  uint32_t texture_id;
137  in->reader() >> texture_id;
138  impl->create_video_sink(texture_id);
139 
140  auto reply = dbus::Message::make_method_return(in);
141  bus->send(reply);
142  }
143 
144  bool does_client_have_access(const std::string& context, const std::string& uri)
145  {
146  if (context.empty() || uri.empty())
147  {
148  std::cout << "Client denied access since context or uri are empty" << std::endl;
149  return false;
150  }
151 
152  if (context == "unconfined")
153  {
154  std::cout << "Client allowed access since it's unconfined" << std::endl;
155  return true;
156  }
157 
158  size_t pos = context.find_first_of('_');
159  if (pos == std::string::npos)
160  {
161  std::cout << "Client denied access since it's an invalid apparmor security context" << std::endl;
162  return false;
163  }
164 
165  const std::string pkgname = context.substr(0, pos);
166  std::cout << "client pkgname: " << pkgname << std::endl;
167  std::cout << "uri: " << uri << std::endl;
168 
169  // All confined apps can access their own files
170  if (uri.find(std::string(".local/share/" + pkgname + "/")) != std::string::npos
171  || uri.find(std::string(".cache/" + pkgname + "/")) != std::string::npos)
172  {
173  std::cout << "Client can access content in ~/.local/share/" << pkgname << " or ~/.cache/" << pkgname << std::endl;
174  return true;
175  }
176  else if (uri.find(std::string("opt/click.ubuntu.com/")) != std::string::npos
177  && uri.find(pkgname) != std::string::npos)
178  {
179  std::cout << "Client can access content in own opt directory" << std::endl;
180  return true;
181  }
182  else if ((uri.find(std::string("/system/media/audio/ui/")) != std::string::npos
183  || uri.find(std::string("/android/system/media/audio/ui/")) != std::string::npos)
184  && pkgname == "com.ubuntu.camera")
185  {
186  std::cout << "Camera app can access ui sounds" << std::endl;
187  return true;
188  }
189  // TODO: Check if the trust store previously allowed direct access to uri
190 
191  // Check in ~/Music and ~/Videos
192  // TODO: when the trust store lands, check it to see if this app can access the dirs and
193  // then remove the explicit whitelist of the music-app, and gallery-app
194  else if ((pkgname == "com.ubuntu.music" || pkgname == "com.ubuntu.gallery") &&
195  (uri.find(std::string("Music/")) != std::string::npos
196  || uri.find(std::string("Videos/")) != std::string::npos
197  || uri.find(std::string("/media")) != std::string::npos))
198  {
199  std::cout << "Client can access content in ~/Music or ~/Videos" << std::endl;
200  return true;
201  }
202  else if (uri.find(std::string("/usr/share/sounds")) != std::string::npos)
203  {
204  std::cout << "Client can access content in /usr/share/sounds" << std::endl;
205  return true;
206  }
207  else if (uri.find(std::string("http://")) != std::string::npos
208  || uri.find(std::string("rtsp://")) != std::string::npos)
209  {
210  std::cout << "Client can access streaming content" << std::endl;
211  return true;
212  }
213  else
214  {
215  std::cout << "Client denied access to open_uri()" << std::endl;
216  return false;
217  }
218  }
219 
220  void handle_key(const core::dbus::Message::Ptr& in)
221  {
222  auto reply = dbus::Message::make_method_return(in);
223  reply->writer() << impl->key();
224  bus->send(reply);
225  }
226 
227  void handle_open_uri(const core::dbus::Message::Ptr& in)
228  {
229  dbus_stub.get_connection_app_armor_security_async(in->sender(), [this, in](const std::string& profile)
230  {
231  Track::UriType uri;
232  in->reader() >> uri;
233 
234  bool have_access = does_client_have_access(profile, uri);
235 
236  auto reply = dbus::Message::make_method_return(in);
237  reply->writer() << (have_access ? impl->open_uri(uri) : false);
238 
239  bus->send(reply);
240  });
241  }
242 
243  template<typename Property>
245  const typename Property::ValueType& value,
246  const dbus::Signal
247  <
248  core::dbus::interfaces::Properties::Signals::PropertiesChanged,
249  core::dbus::interfaces::Properties::Signals::PropertiesChanged::ArgumentType
250  >::Ptr& signal)
251  {
252  typedef std::map<std::string, dbus::types::Variant> Dictionary;
253 
254  static const std::vector<std::string> the_empty_list_of_invalidated_properties;
255 
256  Dictionary dict; dict[Property::name()] = dbus::types::Variant::encode(value);
257 
258  signal->emit(std::make_tuple(
259  dbus::traits::Service<typename Property::Interface>::interface_name(),
260  dict,
261  the_empty_list_of_invalidated_properties));
262  }
263 
265  std::string identity;
266  dbus::Bus::Ptr bus;
267  dbus::Object::Ptr object;
268  dbus::Object::Ptr apparmor_session;
269 
271 
273 
274  struct Signals
275  {
276  typedef core::dbus::Signal<mpris::Player::Signals::Seeked, mpris::Player::Signals::Seeked::ArgumentType> DBusSeekedToSignal;
277  typedef core::dbus::Signal<mpris::Player::Signals::EndOfStream, mpris::Player::Signals::EndOfStream::ArgumentType> DBusEndOfStreamSignal;
278  typedef core::dbus::Signal<mpris::Player::Signals::PlaybackStatusChanged, mpris::Player::Signals::PlaybackStatusChanged::ArgumentType> DBusPlaybackStatusChangedSignal;
279  typedef core::dbus::Signal<mpris::Player::Signals::VideoDimensionChanged, mpris::Player::Signals::VideoDimensionChanged::ArgumentType> DBusVideoDimensionChangedSignal;
280 
281  Signals(const std::shared_ptr<DBusSeekedToSignal>& remote_seeked,
282  const std::shared_ptr<DBusEndOfStreamSignal>& remote_eos,
283  const std::shared_ptr<DBusPlaybackStatusChangedSignal>& remote_playback_status_changed,
284  const std::shared_ptr<DBusVideoDimensionChangedSignal>& remote_video_dimension_changed)
285  {
286  seeked_to.connect([remote_seeked](std::uint64_t value)
287  {
288  remote_seeked->emit(value);
289  });
290 
291  end_of_stream.connect([remote_eos]()
292  {
293  remote_eos->emit();
294  });
295 
296  playback_status_changed.connect([remote_playback_status_changed](const media::Player::PlaybackStatus& status)
297  {
298  remote_playback_status_changed->emit(status);
299  });
300 
301  video_dimension_changed.connect([remote_video_dimension_changed](uint64_t mask)
302  {
303  remote_video_dimension_changed->emit(mask);
304  });
305  }
306 
307  core::Signal<int64_t> seeked_to;
308  core::Signal<void> end_of_stream;
309  core::Signal<media::Player::PlaybackStatus> playback_status_changed;
310  core::Signal<uint64_t> video_dimension_changed;
311  } signals;
312 
313 };
314 
315 media::PlayerSkeleton::PlayerSkeleton(const media::PlayerSkeleton::Configuration& config)
316  : d(new Private{this, config.identity, config.bus, config.session})
317 {
318  // Setup method handlers for mpris::Player methods.
319  auto next = std::bind(&Private::handle_next, d, std::placeholders::_1);
320  d->object->install_method_handler<mpris::Player::Next>(next);
321 
322  auto previous = std::bind(&Private::handle_previous, d, std::placeholders::_1);
323  d->object->install_method_handler<mpris::Player::Previous>(previous);
324 
325  auto pause = std::bind(&Private::handle_pause, d, std::placeholders::_1);
326  d->object->install_method_handler<mpris::Player::Pause>(pause);
327 
328  auto stop = std::bind(&Private::handle_stop, d, std::placeholders::_1);
329  d->object->install_method_handler<mpris::Player::Stop>(stop);
330 
331  auto play = std::bind(&Private::handle_play, d, std::placeholders::_1);
332  d->object->install_method_handler<mpris::Player::Play>(play);
333 
334  auto play_pause = std::bind(&Private::handle_play_pause, d, std::placeholders::_1);
335  d->object->install_method_handler<mpris::Player::PlayPause>(play_pause);
336 
337  auto seek = std::bind(&Private::handle_seek, d, std::placeholders::_1);
338  d->object->install_method_handler<mpris::Player::Seek>(seek);
339 
340  auto set_position = std::bind(&Private::handle_set_position, d, std::placeholders::_1);
341  d->object->install_method_handler<mpris::Player::SetPosition>(set_position);
342 
343  auto open_uri = std::bind(&Private::handle_open_uri, d, std::placeholders::_1);
344  d->object->install_method_handler<mpris::Player::OpenUri>(open_uri);
345 
346  // All the method handlers that exceed the mpris spec go here.
347  d->object->install_method_handler<mpris::Player::CreateVideoSink>(
349  d,
350  std::placeholders::_1));
351 
352  d->object->install_method_handler<mpris::Player::Key>(
353  std::bind(&Private::handle_key,
354  d,
355  std::placeholders::_1));
356 }
357 
359 {
360  // The session object may outlive the private instance
361  // so uninstall all method handlers.
362  d->object->uninstall_method_handler<mpris::Player::Next>();
363  d->object->uninstall_method_handler<mpris::Player::Previous>();
364  d->object->uninstall_method_handler<mpris::Player::Pause>();
365  d->object->uninstall_method_handler<mpris::Player::Stop>();
366  d->object->uninstall_method_handler<mpris::Player::Play>();
367  d->object->uninstall_method_handler<mpris::Player::PlayPause>();
368  d->object->uninstall_method_handler<mpris::Player::Seek>();
369  d->object->uninstall_method_handler<mpris::Player::SetPosition>();
370  d->object->uninstall_method_handler<mpris::Player::OpenUri>();
371  d->object->uninstall_method_handler<mpris::Player::CreateVideoSink>();
372  d->object->uninstall_method_handler<mpris::Player::Key>();
373 }
374 
375 const core::Property<bool>& media::PlayerSkeleton::can_play() const
376 {
377  return *d->skeleton.properties.can_play;
378 }
379 
380 const core::Property<bool>& media::PlayerSkeleton::can_pause() const
381 {
382  return *d->skeleton.properties.can_pause;
383 }
384 
385 const core::Property<bool>& media::PlayerSkeleton::can_seek() const
386 {
387  return *d->skeleton.properties.can_seek;
388 }
389 
390 const core::Property<bool>& media::PlayerSkeleton::can_go_previous() const
391 {
392  return *d->skeleton.properties.can_go_previous;
393 }
394 
395 const core::Property<bool>& media::PlayerSkeleton::can_go_next() const
396 {
397  return *d->skeleton.properties.can_go_next;
398 }
399 
400 const core::Property<bool>& media::PlayerSkeleton::is_video_source() const
401 {
402  return *d->skeleton.properties.is_video_source;
403 }
404 
405 const core::Property<bool>& media::PlayerSkeleton::is_audio_source() const
406 {
407  return *d->skeleton.properties.is_audio_source;
408 }
409 
410 const core::Property<media::Player::PlaybackStatus>& media::PlayerSkeleton::playback_status() const
411 {
412  return *d->skeleton.properties.typed_playback_status;
413 }
414 
415 const core::Property<media::Player::LoopStatus>& media::PlayerSkeleton::loop_status() const
416 {
417  return *d->skeleton.properties.typed_loop_status;
418 }
419 
420 const core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::playback_rate() const
421 {
422  return *d->skeleton.properties.playback_rate;
423 }
424 
425 const core::Property<bool>& media::PlayerSkeleton::is_shuffle() const
426 {
427  return *d->skeleton.properties.is_shuffle;
428 }
429 
430 const core::Property<media::Track::MetaData>& media::PlayerSkeleton::meta_data_for_current_track() const
431 {
432  return *d->skeleton.properties.typed_meta_data_for_current_track;
433 }
434 
435 const core::Property<media::Player::Volume>& media::PlayerSkeleton::volume() const
436 {
437  return *d->skeleton.properties.volume;
438 }
439 
440 const core::Property<int64_t>& media::PlayerSkeleton::position() const
441 {
442  return *d->skeleton.properties.position;
443 }
444 
445 const core::Property<int64_t>& media::PlayerSkeleton::duration() const
446 {
447  return *d->skeleton.properties.duration;
448 }
449 
450 const core::Property<media::Player::AudioStreamRole>& media::PlayerSkeleton::audio_stream_role() const
451 {
452  return *d->skeleton.properties.audio_stream_role;
453 }
454 
455 const core::Property<media::Player::Orientation>& media::PlayerSkeleton::orientation() const
456 {
457  return *d->skeleton.properties.orientation;
458 }
459 
460 const core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::minimum_playback_rate() const
461 {
462  return *d->skeleton.properties.minimum_playback_rate;
463 }
464 
465 const core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::maximum_playback_rate() const
466 {
467  return *d->skeleton.properties.maximum_playback_rate;
468 }
469 
470 core::Property<media::Player::LoopStatus>& media::PlayerSkeleton::loop_status()
471 {
472  return *d->skeleton.properties.typed_loop_status;
473 }
474 
475 core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::playback_rate()
476 {
477  return *d->skeleton.properties.playback_rate;
478 }
479 
480 core::Property<bool>& media::PlayerSkeleton::is_shuffle()
481 {
482  return *d->skeleton.properties.is_shuffle;
483 }
484 
485 core::Property<media::Player::Volume>& media::PlayerSkeleton::volume()
486 {
487  return *d->skeleton.properties.volume;
488 }
489 
490 core::Property<int64_t>& media::PlayerSkeleton::position()
491 {
492  return *d->skeleton.properties.position;
493 }
494 
495 core::Property<int64_t>& media::PlayerSkeleton::duration()
496 {
497  return *d->skeleton.properties.duration;
498 }
499 
500 core::Property<media::Player::AudioStreamRole>& media::PlayerSkeleton::audio_stream_role()
501 {
502  return *d->skeleton.properties.audio_stream_role;
503 }
504 
505 core::Property<media::Player::Orientation>& media::PlayerSkeleton::orientation()
506 {
507  return *d->skeleton.properties.orientation;
508 }
509 
510 core::Property<media::Player::PlaybackStatus>& media::PlayerSkeleton::playback_status()
511 {
512  return *d->skeleton.properties.typed_playback_status;
513 }
514 
515 core::Property<bool>& media::PlayerSkeleton::can_play()
516 {
517  return *d->skeleton.properties.can_play;
518 }
519 
520 core::Property<bool>& media::PlayerSkeleton::can_pause()
521 {
522  return *d->skeleton.properties.can_pause;
523 }
524 
525 core::Property<bool>& media::PlayerSkeleton::can_seek()
526 {
527  return *d->skeleton.properties.can_seek;
528 }
529 
530 core::Property<bool>& media::PlayerSkeleton::can_go_previous()
531 {
532  return *d->skeleton.properties.can_go_previous;
533 }
534 
535 core::Property<bool>& media::PlayerSkeleton::can_go_next()
536 {
537  return *d->skeleton.properties.can_go_next;
538 }
539 
540 core::Property<bool>& media::PlayerSkeleton::is_video_source()
541 {
542  return *d->skeleton.properties.is_video_source;
543 }
544 
545 core::Property<bool>& media::PlayerSkeleton::is_audio_source()
546 {
547  return *d->skeleton.properties.is_audio_source;
548 }
549 
550 core::Property<media::Track::MetaData>& media::PlayerSkeleton::meta_data_for_current_track()
551 {
552  return *d->skeleton.properties.typed_meta_data_for_current_track;
553 }
554 
555 core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::minimum_playback_rate()
556 {
557  return *d->skeleton.properties.minimum_playback_rate;
558 }
559 
560 core::Property<media::Player::PlaybackRate>& media::PlayerSkeleton::maximum_playback_rate()
561 {
562  return *d->skeleton.properties.maximum_playback_rate;
563 }
564 
565 const core::Signal<int64_t>& media::PlayerSkeleton::seeked_to() const
566 {
567  return d->signals.seeked_to;
568 }
569 
570 core::Signal<int64_t>& media::PlayerSkeleton::seeked_to()
571 {
572  return d->signals.seeked_to;
573 }
574 
575 const core::Signal<void>& media::PlayerSkeleton::end_of_stream() const
576 {
577  return d->signals.end_of_stream;
578 }
579 
580 core::Signal<void>& media::PlayerSkeleton::end_of_stream()
581 {
582  return d->signals.end_of_stream;
583 }
584 
585 core::Signal<media::Player::PlaybackStatus>& media::PlayerSkeleton::playback_status_changed()
586 {
587  return d->signals.playback_status_changed;
588 }
589 
590 const core::Signal<uint64_t>& media::PlayerSkeleton::video_dimension_changed() const
591 {
592  return d->signals.video_dimension_changed;
593 }
594 
595 core::Signal<uint64_t>& media::PlayerSkeleton::video_dimension_changed()
596 {
597  return d->signals.video_dimension_changed;
598 }
void handle_previous(const core::dbus::Message::Ptr &msg)
mpris::Player::Skeleton skeleton
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
virtual const core::Signal< void > & end_of_stream() const
virtual const core::Property< int64_t > & duration() const
virtual const core::Property< bool > & can_seek() const
virtual const core::Property< PlaybackRate > & maximum_playback_rate() const
virtual const core::Property< bool > & is_shuffle() const
virtual const core::Property< bool > & can_go_next() const
virtual const core::Property< int64_t > & position() const
virtual const core::Property< bool > & can_go_previous() const
virtual void previous()=0
void handle_set_position(const core::dbus::Message::Ptr &)
bool does_client_have_access(const std::string &context, const std::string &uri)
virtual const core::Property< bool > & can_play() const
core::dbus::Signal< Signals::VideoDimensionChanged, Signals::VideoDimensionChanged::ArgumentType >::Ptr video_dimension_changed
Definition: player.h:355
void handle_play_pause(const core::dbus::Message::Ptr &msg)
virtual const core::Property< Track::MetaData > & meta_data_for_current_track() const
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)
Private(media::PlayerSkeleton *player, const std::string &identity, const std::shared_ptr< core::dbus::Bus > &bus, const std::shared_ptr< core::dbus::Object > &session)
virtual const core::Signal< uint64_t > & video_dimension_changed() const
virtual bool open_uri(const Track::UriType &uri)=0
virtual const core::Signal< int64_t > & seeked_to() const
virtual const core::Property< PlaybackRate > & playback_rate() const
PlayerSkeleton(const Configuration &configuration)
virtual void create_video_sink(uint32_t texture_id)=0
virtual const core::Property< AudioStreamRole > & audio_stream_role() const
Signals(const std::shared_ptr< DBusSeekedToSignal > &remote_seeked, const std::shared_ptr< DBusEndOfStreamSignal > &remote_eos, const std::shared_ptr< DBusPlaybackStatusChangedSignal > &remote_playback_status_changed, const std::shared_ptr< DBusVideoDimensionChangedSignal > &remote_video_dimension_changed)
core::dbus::Signal< mpris::Player::Signals::EndOfStream, mpris::Player::Signals::EndOfStream::ArgumentType > DBusEndOfStreamSignal
media::PlayerSkeleton * impl
core::dbus::Signal< mpris::Player::Signals::VideoDimensionChanged, mpris::Player::Signals::VideoDimensionChanged::ArgumentType > DBusVideoDimensionChangedSignal
void handle_pause(const core::dbus::Message::Ptr &msg)
core::Signal< uint64_t > video_dimension_changed
core::dbus::Signal< mpris::Player::Signals::PlaybackStatusChanged, mpris::Player::Signals::PlaybackStatusChanged::ArgumentType > DBusPlaybackStatusChangedSignal
virtual const core::Property< PlaybackRate > & minimum_playback_rate() const
struct media::PlayerSkeleton::Private::Signals signals
void handle_seek(const core::dbus::Message::Ptr &in)
virtual const core::Property< Orientation > & orientation() const
void get_connection_app_armor_security_async(const std::string &name, std::function< void(const std::string &)> handler)
Definition: apparmor.h:75
struct mpris::Player::Skeleton::@15 signals
org::freedesktop::dbus::DBus::Stub dbus_stub
void handle_open_uri(const core::dbus::Message::Ptr &in)
core::dbus::Signal< Signals::Seeked, Signals::Seeked::ArgumentType >::Ptr seeked_to
Definition: player.h:352
virtual const core::Property< Volume > & volume() const
std::string UriType
Definition: track.h:40
virtual PlayerKey key() const =0
void handle_next(const core::dbus::Message::Ptr &msg)
virtual core::Signal< PlaybackStatus > & playback_status_changed()
void on_property_value_changed(const typename Property::ValueType &value, const dbus::Signal< core::dbus::interfaces::Properties::Signals::PropertiesChanged, core::dbus::interfaces::Properties::Signals::PropertiesChanged::ArgumentType >::Ptr &signal)
virtual const core::Property< bool > & is_audio_source() const
core::dbus::Signal< mpris::Player::Signals::Seeked, mpris::Player::Signals::Seeked::ArgumentType > DBusSeekedToSignal
core::dbus::Signal< Signals::EndOfStream, Signals::EndOfStream::ArgumentType >::Ptr end_of_stream
Definition: player.h:353
core::Signal< media::Player::PlaybackStatus > playback_status_changed
core::dbus::Signal< Signals::PlaybackStatusChanged, Signals::PlaybackStatusChanged::ArgumentType >::Ptr playback_status_changed
Definition: player.h:354
void handle_create_video_sink(const core::dbus::Message::Ptr &in)
void handle_key(const core::dbus::Message::Ptr &in)
virtual void seek_to(const std::chrono::microseconds &offset)=0