Music Hub  ..
A session-wide music playback service
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
player_stub.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 <core/media/service.h>
21 #include <core/media/track_list.h>
22 
23 #include "codec.h"
24 #include "player_stub.h"
25 #include "player_traits.h"
26 #include "property_stub.h"
27 #include "the_session_bus.h"
28 #include "track_list_stub.h"
29 
30 #include "mpris/player.h"
31 
32 #include <core/dbus/property.h>
33 #include <core/dbus/types/object_path.h>
34 
35 // Hybris
36 #include <hybris/media/media_codec_layer.h>
37 #include <hybris/media/surface_texture_client_hybris.h>
38 
39 #include <limits>
40 
41 #define UNUSED __attribute__((unused))
42 
43 namespace dbus = core::dbus;
44 namespace media = core::ubuntu::media;
45 
47 {
48  Private(const std::shared_ptr<Service>& parent,
49  const std::shared_ptr<core::dbus::Object>& object
50  ) : parent(parent),
51  texture_id(0),
52  igbc_wrapper(nullptr),
53  glc_wrapper(nullptr),
54  decoding_session(nullptr),
55  frame_available_cb(nullptr),
56  frame_available_context(nullptr),
57  object(object),
59  {
60  // Link the properties from the server side to the client side over the bus
61  object->get_property<mpris::Player::Properties::CanPlay>(),
62  object->get_property<mpris::Player::Properties::CanPause>(),
63  object->get_property<mpris::Player::Properties::CanSeek>(),
64  object->get_property<mpris::Player::Properties::CanControl>(),
65  object->get_property<mpris::Player::Properties::CanGoNext>(),
66  object->get_property<mpris::Player::Properties::CanGoPrevious>(),
67  object->get_property<mpris::Player::Properties::IsVideoSource>(),
68  object->get_property<mpris::Player::Properties::IsAudioSource>(),
69  object->get_property<mpris::Player::Properties::TypedPlaybackStatus>(),
70  object->get_property<mpris::Player::Properties::TypedLoopStatus>(),
71  object->get_property<mpris::Player::Properties::PlaybackRate>(),
72  object->get_property<mpris::Player::Properties::Shuffle>(),
73  object->get_property<mpris::Player::Properties::TypedMetaData>(),
74  object->get_property<mpris::Player::Properties::Volume>(),
75  object->get_property<mpris::Player::Properties::Position>(),
76  object->get_property<mpris::Player::Properties::Duration>(),
77  object->get_property<mpris::Player::Properties::AudioStreamRole>(),
78  object->get_property<mpris::Player::Properties::Orientation>(),
79  object->get_property<mpris::Player::Properties::Lifetime>(),
80  object->get_property<mpris::Player::Properties::MinimumRate>(),
81  object->get_property<mpris::Player::Properties::MaximumRate>()
82  },
83  signals
84  {
85  object->get_signal<mpris::Player::Signals::Seeked>(),
86  object->get_signal<mpris::Player::Signals::EndOfStream>(),
87  object->get_signal<mpris::Player::Signals::PlaybackStatusChanged>(),
88  object->get_signal<mpris::Player::Signals::VideoDimensionChanged>()
89  }
90  {
91  auto op = object->invoke_method_synchronously<mpris::Player::Key, media::Player::PlayerKey>();
92  decoding_session = decoding_service_create_session(op.value());
93  }
94 
96  {
97  }
98 
99  static void on_frame_available_cb(UNUSED GLConsumerWrapperHybris wrapper, void *context)
100  {
101  if (context != nullptr) {
102  Private *p = static_cast<Private*>(context);
103  p->on_frame_available();
104  }
105  else
106  std::cerr << "context is nullptr, can't call on_frame_available()" << std::endl;
107  }
108 
110  {
111  if (frame_available_cb != nullptr) {
113  }
114  else
115  std::cerr << "frame_available_cb is nullptr, can't call frame_available_cb()" << std::endl;
116  }
117 
118  void set_frame_available_cb(FrameAvailableCb cb, void *context)
119  {
120  frame_available_cb = cb;
121  frame_available_context = context;
122 
123  gl_consumer_set_frame_available_cb(glc_wrapper, &Private::on_frame_available_cb, static_cast<void*>(this));
124  }
125 
129  {
130  igbc_wrapper = decoding_service_get_igraphicbufferconsumer();
131  glc_wrapper = gl_consumer_create_by_id_with_igbc(texture_id, igbc_wrapper);
132 
133  }
134 
135  std::shared_ptr<Service> parent;
136  std::shared_ptr<TrackList> track_list;
137 
138  uint32_t texture_id;
139  IGBCWrapperHybris igbc_wrapper;
141 
142  DSSessionWrapperHybris decoding_session;
143 
146 
147  dbus::Object::Ptr object;
148 
149  struct
150  {
151  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanPlay>> can_play;
152  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanPause>> can_pause;
153  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanSeek>> can_seek;
154  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanControl>> can_control;
155  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanGoNext>> can_go_next;
156  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanGoPrevious>> can_go_previous;
157  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::IsVideoSource>> is_video_source;
158  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::IsAudioSource>> is_audio_source;
159 
160  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::TypedPlaybackStatus>> playback_status;
161  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::TypedLoopStatus>> loop_status;
162  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::PlaybackRate>> playback_rate;
163  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Shuffle>> is_shuffle;
164  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::TypedMetaData>> meta_data_for_current_track;
165  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Volume>> volume;
166  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Position>> position;
167  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Duration>> duration;
168  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::AudioStreamRole>> audio_role;
169  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Orientation>> orientation;
170  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Lifetime>> lifetime;
171  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MinimumRate>> minimum_playback_rate;
172  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MaximumRate>> maximum_playback_rate;
173  } properties;
174 
175  struct Signals
176  {
177  typedef core::dbus::Signal<mpris::Player::Signals::Seeked, mpris::Player::Signals::Seeked::ArgumentType> DBusSeekedToSignal;
178  typedef core::dbus::Signal<mpris::Player::Signals::EndOfStream, mpris::Player::Signals::EndOfStream::ArgumentType> DBusEndOfStreamSignal;
179  typedef core::dbus::Signal<mpris::Player::Signals::PlaybackStatusChanged, mpris::Player::Signals::PlaybackStatusChanged::ArgumentType> DBusPlaybackStatusChangedSignal;
180  typedef core::dbus::Signal<mpris::Player::Signals::VideoDimensionChanged, mpris::Player::Signals::VideoDimensionChanged::ArgumentType> DBusVideoDimensionChangedSignal;
181 
182  Signals(const std::shared_ptr<DBusSeekedToSignal>& seeked,
183  const std::shared_ptr<DBusEndOfStreamSignal>& eos,
184  const std::shared_ptr<DBusPlaybackStatusChangedSignal>& status,
185  const std::shared_ptr<DBusVideoDimensionChangedSignal>& d)
186  : playback_complete_cb(nullptr),
187  playback_complete_context(nullptr),
188  seeked_to(),
189  end_of_stream(),
192  dbus
193  {
194  seeked,
195  eos,
196  status,
197  d
198  }
199  {
200  dbus.seeked_to->connect([this](std::uint64_t value)
201  {
202  std::cout << "seeked_to signal arrived via the bus." << std::endl;
203  seeked_to(value);
204  });
205 
206  dbus.end_of_stream->connect([this]()
207  {
208  std::cout << "EndOfStream signal arrived via the bus." << std::endl;
211  end_of_stream();
212  });
213 
214  dbus.playback_status_changed->connect([this](const media::Player::PlaybackStatus& status)
215  {
216  std::cout << "PlaybackStatusChanged signal arrived via the bus." << std::endl;
217  playback_status_changed(status);
218  });
219 
220  dbus.video_dimension_changed->connect([this](uint64_t mask)
221  {
222  std::cout << "VideoDimensionChanged signal arrived via the bus." << std::endl;
224  });
225  }
226 
228  {
230  playback_complete_context = context;
231  }
232 
235  core::Signal<int64_t> seeked_to;
236  core::Signal<void> end_of_stream;
237  core::Signal<media::Player::PlaybackStatus> playback_status_changed;
238  core::Signal<uint64_t> video_dimension_changed;
239 
240  struct DBus
241  {
242  std::shared_ptr<DBusSeekedToSignal> seeked_to;
243  std::shared_ptr<DBusEndOfStreamSignal> end_of_stream;
244  std::shared_ptr<DBusPlaybackStatusChangedSignal> playback_status_changed;
245  std::shared_ptr<DBusVideoDimensionChangedSignal> video_dimension_changed;
246  } dbus;
247  } signals;
248 };
249 
251  const std::shared_ptr<Service>& parent,
252  const std::shared_ptr<core::dbus::Object>& object)
253  : d(new Private{parent, object})
254 {
255 }
256 
258 {
259 }
260 
261 std::shared_ptr<media::TrackList> media::PlayerStub::track_list()
262 {
263  if (!d->track_list)
264  {
265  d->track_list = std::make_shared<media::TrackListStub>(
266  shared_from_this(),
267  dbus::types::ObjectPath(d->object->path().as_string() + "/TrackList"));
268  }
269  return d->track_list;
270 }
271 
273 {
274  auto op = d->object->invoke_method_synchronously<mpris::Player::Key, media::Player::PlayerKey>();
275 
276  return op.value();
277 }
278 
280 {
281  auto op = d->object->invoke_method_synchronously<mpris::Player::OpenUri, bool>(uri);
282 
283  return op.value();
284 }
285 
286 bool media::PlayerStub::open_uri(const Track::UriType& uri, const Player::HeadersType& headers)
287 {
288  auto op = d->object->invoke_method_synchronously<mpris::Player::OpenUriExtended, bool>(uri, headers);
289 
290  return op.value();
291 }
292 
293 void media::PlayerStub::create_video_sink(uint32_t texture_id)
294 {
295  auto op = d->object->invoke_method_synchronously<mpris::Player::CreateVideoSink, void>(texture_id);
296  d->texture_id = texture_id;
297  d->get_gl_consumer();
298 
299  if (op.is_error())
300  throw std::runtime_error("Problem creating new video sink instance on remote object");
301 }
302 
304 {
305  return d->glc_wrapper;
306 }
307 
309 {
310  auto op = d->object->invoke_method_synchronously<mpris::Player::Next, void>();
311 
312  if (op.is_error())
313  throw std::runtime_error("Problem switching to next track on remote object");
314 }
315 
317 {
318  auto op = d->object->invoke_method_synchronously<mpris::Player::Previous, void>();
319 
320  if (op.is_error())
321  throw std::runtime_error("Problem switching to previous track on remote object");
322 }
323 
325 {
326  auto op = d->object->invoke_method_synchronously<mpris::Player::Play, void>();
327 
328  if (op.is_error())
329  throw std::runtime_error("Problem starting playback on remote object");
330 }
331 
333 {
334  auto op = d->object->invoke_method_synchronously<mpris::Player::Pause, void>();
335 
336  if (op.is_error())
337  throw std::runtime_error("Problem pausing playback on remote object");
338 }
339 
340 void media::PlayerStub::seek_to(const std::chrono::microseconds& offset)
341 {
342  auto op = d->object->invoke_method_synchronously<mpris::Player::Seek, void, uint64_t>(offset.count());
343 
344  if (op.is_error())
345  throw std::runtime_error("Problem seeking on remote object");
346 }
347 
349 {
350  auto op = d->object->invoke_method_synchronously<mpris::Player::Stop, void>();
351 
352  if (op.is_error())
353  throw std::runtime_error("Problem stopping playback on remote object");
354 }
355 
357 {
358  d->set_frame_available_cb(cb, context);
359 }
360 
362 {
363  d->signals.set_playback_complete_cb(cb, context);
364 }
365 
366 const core::Property<bool>& media::PlayerStub::can_play() const
367 {
368  return *d->properties.can_play;
369 }
370 
371 const core::Property<bool>& media::PlayerStub::can_pause() const
372 {
373  return *d->properties.can_pause;
374 }
375 
376 const core::Property<bool>& media::PlayerStub::can_seek() const
377 {
378  return *d->properties.can_seek;
379 }
380 
381 const core::Property<bool>& media::PlayerStub::can_go_previous() const
382 {
383  return *d->properties.can_go_previous;
384 }
385 
386 const core::Property<bool>& media::PlayerStub::can_go_next() const
387 {
388  return *d->properties.can_go_next;
389 }
390 
391 const core::Property<bool>& media::PlayerStub::is_video_source() const
392 {
393  return *d->properties.is_video_source;
394 }
395 
396 const core::Property<bool>& media::PlayerStub::is_audio_source() const
397 {
398  return *d->properties.is_audio_source;
399 }
400 
401 const core::Property<media::Player::PlaybackStatus>& media::PlayerStub::playback_status() const
402 {
403  return *d->properties.playback_status;
404 }
405 
406 const core::Property<media::Player::LoopStatus>& media::PlayerStub::loop_status() const
407 {
408  return *d->properties.loop_status;
409 }
410 
411 const core::Property<media::Player::PlaybackRate>& media::PlayerStub::playback_rate() const
412 {
413  return *d->properties.playback_rate;
414 }
415 
416 const core::Property<bool>& media::PlayerStub::is_shuffle() const
417 {
418  return *d->properties.is_shuffle;
419 }
420 
421 const core::Property<media::Track::MetaData>& media::PlayerStub::meta_data_for_current_track() const
422 {
423  return *d->properties.meta_data_for_current_track;
424 }
425 
426 const core::Property<media::Player::Volume>& media::PlayerStub::volume() const
427 {
428  return *d->properties.volume;
429 }
430 
431 const core::Property<int64_t>& media::PlayerStub::position() const
432 {
433  return *d->properties.position;
434 }
435 
436 const core::Property<int64_t>& media::PlayerStub::duration() const
437 {
438  return *d->properties.duration;
439 }
440 
441 const core::Property<media::Player::AudioStreamRole>& media::PlayerStub::audio_stream_role() const
442 {
443  return *d->properties.audio_role;
444 }
445 
446 const core::Property<media::Player::Orientation>& media::PlayerStub::orientation() const
447 {
448  return *d->properties.orientation;
449 }
450 
451 const core::Property<media::Player::Lifetime>& media::PlayerStub::lifetime() const
452 {
453  return *d->properties.lifetime;
454 }
455 
456 const core::Property<media::Player::PlaybackRate>& media::PlayerStub::minimum_playback_rate() const
457 {
458  return *d->properties.minimum_playback_rate;
459 }
460 
461 const core::Property<media::Player::PlaybackRate>& media::PlayerStub::maximum_playback_rate() const
462 {
463  return *d->properties.maximum_playback_rate;
464 }
465 
466 core::Property<media::Player::LoopStatus>& media::PlayerStub::loop_status()
467 {
468  return *d->properties.loop_status;
469 }
470 
471 core::Property<media::Player::PlaybackRate>& media::PlayerStub::playback_rate()
472 {
473  return *d->properties.playback_rate;
474 }
475 
476 core::Property<bool>& media::PlayerStub::is_shuffle()
477 {
478  return *d->properties.is_shuffle;
479 }
480 
481 core::Property<media::Player::Volume>& media::PlayerStub::volume()
482 {
483  return *d->properties.volume;
484 }
485 
486 core::Property<media::Player::AudioStreamRole>& media::PlayerStub::audio_stream_role()
487 {
488  return *d->properties.audio_role;
489 }
490 
491 core::Property<media::Player::Lifetime>& media::PlayerStub::lifetime()
492 {
493  return *d->properties.lifetime;
494 }
495 
496 const core::Signal<int64_t>& media::PlayerStub::seeked_to() const
497 {
498  return d->signals.seeked_to;
499 }
500 
501 const core::Signal<void>& media::PlayerStub::end_of_stream() const
502 {
503  return d->signals.end_of_stream;
504 }
505 
506 core::Signal<media::Player::PlaybackStatus>& media::PlayerStub::playback_status_changed()
507 {
508  return d->signals.playback_status_changed;
509 }
510 
511 const core::Signal<uint64_t>& media::PlayerStub::video_dimension_changed() const
512 {
513  return d->signals.video_dimension_changed;
514 }
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::CanPlay > > can_play
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::CanControl > > can_control
void * GLConsumerWrapperHybris
Definition: player.h:44
IGBCWrapperHybris igbc_wrapper
std::shared_ptr< DBusEndOfStreamSignal > end_of_stream
std::shared_ptr< DBusVideoDimensionChangedSignal > video_dimension_changed
void set_frame_available_cb(FrameAvailableCb cb, void *context)
virtual void create_video_sink(uint32_t texture_id)
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::IsAudioSource > > is_audio_source
virtual const core::Property< int64_t > & position() const
virtual const core::Property< Orientation > & orientation() const
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::MinimumRate > > minimum_playback_rate
virtual const core::Property< bool > & is_video_source() const
struct media::PlayerStub::Private::Signals signals
virtual const core::Signal< uint64_t > & video_dimension_changed() const
virtual const core::Signal< void > & end_of_stream() const
core::Signal< void > end_of_stream
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::Lifetime > > lifetime
static void on_frame_available_cb(UNUSED GLConsumerWrapperHybris wrapper, void *context)
Definition: player_stub.cpp:99
dbus::Object::Ptr object
virtual const core::Property< int64_t > & duration() const
std::shared_ptr< DBusSeekedToSignal > seeked_to
virtual const core::Property< bool > & is_audio_source() const
core::dbus::Signal< mpris::Player::Signals::EndOfStream, mpris::Player::Signals::EndOfStream::ArgumentType > DBusEndOfStreamSignal
std::map< std::string, std::string > HeadersType
Definition: player.h:45
std::shared_ptr< Service > parent
core::dbus::Signal< mpris::Player::Signals::VideoDimensionChanged, mpris::Player::Signals::VideoDimensionChanged::ArgumentType > DBusVideoDimensionChangedSignal
virtual const core::Property< bool > & can_pause() const
GLConsumerWrapperHybris glc_wrapper
void(* FrameAvailableCb)(void *context)
Definition: player.h:49
virtual const core::Property< Volume > & volume() const
virtual void set_playback_complete_callback(PlaybackCompleteCb cb, void *context)
struct media::PlayerStub::Private::Signals::DBus dbus
virtual const core::Property< bool > & can_play() const
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::Volume > > volume
virtual GLConsumerWrapperHybris gl_consumer() const
struct media::PlayerStub::Private::@18 properties
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::TypedLoopStatus > > loop_status
virtual const core::Property< bool > & can_go_next() const
core::dbus::Signal< mpris::Player::Signals::Seeked, mpris::Player::Signals::Seeked::ArgumentType > DBusSeekedToSignal
virtual const core::Property< Track::MetaData > & meta_data_for_current_track() const
core::dbus::Signal< mpris::Player::Signals::PlaybackStatusChanged, mpris::Player::Signals::PlaybackStatusChanged::ArgumentType > DBusPlaybackStatusChangedSignal
PlayerStub(const std::shared_ptr< Service > &parent, const std::shared_ptr< core::dbus::Object > &object)
virtual const core::Property< bool > & is_shuffle() const
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::CanPause > > can_pause
Signals(const std::shared_ptr< DBusSeekedToSignal > &seeked, const std::shared_ptr< DBusEndOfStreamSignal > &eos, const std::shared_ptr< DBusPlaybackStatusChangedSignal > &status, const std::shared_ptr< DBusVideoDimensionChangedSignal > &d)
void(* PlaybackCompleteCb)(void *context)
Definition: player.h:50
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::CanGoPrevious > > can_go_previous
virtual core::Signal< PlaybackStatus > & playback_status_changed()
Private(const std::shared_ptr< Service > &parent, const std::shared_ptr< core::dbus::Object > &object)
Definition: player_stub.cpp:48
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::Shuffle > > is_shuffle
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::Duration > > duration
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::TypedMetaData > > meta_data_for_current_track
virtual const core::Signal< int64_t > & seeked_to() const
std::shared_ptr< TrackList > track_list
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::CanSeek > > can_seek
DSSessionWrapperHybris decoding_session
virtual const core::Property< PlaybackStatus > & playback_status() const
virtual const core::Property< AudioStreamRole > & audio_stream_role() const
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::AudioStreamRole > > audio_role
virtual const core::Property< Lifetime > & lifetime() const
virtual PlayerKey key() const
#define UNUSED
Definition: player_stub.cpp:41
virtual const core::Property< PlaybackRate > & minimum_playback_rate() const
virtual const core::Property< bool > & can_seek() const
virtual void set_frame_available_callback(FrameAvailableCb cb, void *context)
FrameAvailableCb frame_available_cb
virtual bool open_uri(const Track::UriType &uri)
std::string UriType
Definition: track.h:40
core::Signal< uint64_t > video_dimension_changed
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::Position > > position
core::Signal< int64_t > seeked_to
void set_playback_complete_cb(PlaybackCompleteCb cb, void *context)
PlaybackCompleteCb playback_complete_cb
virtual void seek_to(const std::chrono::microseconds &offset)
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::Orientation > > orientation
virtual std::shared_ptr< TrackList > track_list()
std::shared_ptr< DBusPlaybackStatusChangedSignal > playback_status_changed
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::TypedPlaybackStatus > > playback_status
virtual const core::Property< PlaybackRate > & playback_rate() const
virtual const core::Property< bool > & can_go_previous() const
virtual const core::Property< PlaybackRate > & maximum_playback_rate() const
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::PlaybackRate > > playback_rate
core::Signal< media::Player::PlaybackStatus > playback_status_changed
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::MaximumRate > > maximum_playback_rate
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::IsVideoSource > > is_video_source
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::CanGoNext > > can_go_next
virtual const core::Property< LoopStatus > & loop_status() const