Music Hub  ..
A session-wide music playback service
player_stub.cpp
Go to the documentation of this file.
1 /*
2  * Copyright © 2013-2015 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  object->get_signal<mpris::Player::Signals::Error>()
90  }
91  {
92  auto op = object->invoke_method_synchronously<mpris::Player::Key, media::Player::PlayerKey>();
93  decoding_session = decoding_service_create_session(op.value());
94  }
95 
97  {
98  }
99 
100  static void on_frame_available_cb(UNUSED GLConsumerWrapperHybris wrapper, void *context)
101  {
102  if (context != nullptr) {
103  Private *p = static_cast<Private*>(context);
104  p->on_frame_available();
105  }
106  else
107  std::cerr << "context is nullptr, can't call on_frame_available()" << std::endl;
108  }
109 
111  {
112  if (frame_available_cb != nullptr) {
114  }
115  else
116  std::cerr << "frame_available_cb is nullptr, can't call frame_available_cb()" << std::endl;
117  }
118 
119  void set_frame_available_cb(FrameAvailableCb cb, void *context)
120  {
121  frame_available_cb = cb;
122  frame_available_context = context;
123 
124  gl_consumer_set_frame_available_cb(glc_wrapper, &Private::on_frame_available_cb, static_cast<void*>(this));
125  }
126 
130  {
131  igbc_wrapper = decoding_service_get_igraphicbufferconsumer();
132  glc_wrapper = gl_consumer_create_by_id_with_igbc(texture_id, igbc_wrapper);
133 
134  }
135 
136  std::shared_ptr<Service> parent;
137  std::shared_ptr<TrackList> track_list;
138 
139  uint32_t texture_id;
140  IGBCWrapperHybris igbc_wrapper;
142 
143  DSSessionWrapperHybris decoding_session;
144 
147 
148  dbus::Object::Ptr object;
149 
150  struct
151  {
152  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanPlay>> can_play;
153  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanPause>> can_pause;
154  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanSeek>> can_seek;
155  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanControl>> can_control;
156  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanGoNext>> can_go_next;
157  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanGoPrevious>> can_go_previous;
158  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::IsVideoSource>> is_video_source;
159  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::IsAudioSource>> is_audio_source;
160 
161  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::TypedPlaybackStatus>> playback_status;
162  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::TypedLoopStatus>> loop_status;
163  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::PlaybackRate>> playback_rate;
164  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Shuffle>> is_shuffle;
165  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::TypedMetaData>> meta_data_for_current_track;
166  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Volume>> volume;
167  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Position>> position;
168  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Duration>> duration;
169  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::AudioStreamRole>> audio_role;
170  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Orientation>> orientation;
171  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Lifetime>> lifetime;
172  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MinimumRate>> minimum_playback_rate;
173  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MaximumRate>> maximum_playback_rate;
174  } properties;
175 
176  struct Signals
177  {
178  typedef core::dbus::Signal<mpris::Player::Signals::Seeked, mpris::Player::Signals::Seeked::ArgumentType> DBusSeekedToSignal;
179  typedef core::dbus::Signal<mpris::Player::Signals::EndOfStream, mpris::Player::Signals::EndOfStream::ArgumentType> DBusEndOfStreamSignal;
180  typedef core::dbus::Signal<mpris::Player::Signals::PlaybackStatusChanged, mpris::Player::Signals::PlaybackStatusChanged::ArgumentType> DBusPlaybackStatusChangedSignal;
181  typedef core::dbus::Signal<mpris::Player::Signals::VideoDimensionChanged, mpris::Player::Signals::VideoDimensionChanged::ArgumentType> DBusVideoDimensionChangedSignal;
182  typedef core::dbus::Signal<mpris::Player::Signals::Error, mpris::Player::Signals::Error::ArgumentType> DBusErrorSignal;
183 
184  Signals(const std::shared_ptr<DBusSeekedToSignal>& seeked,
185  const std::shared_ptr<DBusEndOfStreamSignal>& eos,
186  const std::shared_ptr<DBusPlaybackStatusChangedSignal>& status,
187  const std::shared_ptr<DBusVideoDimensionChangedSignal>& d,
188  const std::shared_ptr<DBusErrorSignal>& e)
189  : playback_complete_cb(nullptr),
190  playback_complete_context(nullptr),
191  seeked_to(),
192  end_of_stream(),
195  error(),
196  dbus
197  {
198  seeked,
199  eos,
200  status,
201  d,
202  e
203  }
204  {
205  dbus.seeked_to->connect([this](std::uint64_t value)
206  {
207  std::cout << "seeked_to signal arrived via the bus." << std::endl;
208  seeked_to(value);
209  });
210 
211  dbus.end_of_stream->connect([this]()
212  {
213  std::cout << "EndOfStream signal arrived via the bus." << std::endl;
216  end_of_stream();
217  });
218 
219  dbus.playback_status_changed->connect([this](const media::Player::PlaybackStatus& status)
220  {
221  std::cout << "PlaybackStatusChanged signal arrived via the bus." << std::endl;
222  playback_status_changed(status);
223  });
224 
225  dbus.video_dimension_changed->connect([this](uint64_t mask)
226  {
227  std::cout << "VideoDimensionChanged signal arrived via the bus." << std::endl;
229  });
230 
231  dbus.error->connect([this](const media::Player::Error& e)
232  {
233  std::cout << "Error signal arrived via the bus (Error: " << e << ")" << std::endl;
234  error(e);
235  });
236  }
237 
239  {
241  playback_complete_context = context;
242  }
243 
246  core::Signal<int64_t> seeked_to;
247  core::Signal<void> end_of_stream;
248  core::Signal<media::Player::PlaybackStatus> playback_status_changed;
249  core::Signal<uint64_t> video_dimension_changed;
250  core::Signal<media::Player::Error> error;
251 
252  struct DBus
253  {
254  std::shared_ptr<DBusSeekedToSignal> seeked_to;
255  std::shared_ptr<DBusEndOfStreamSignal> end_of_stream;
256  std::shared_ptr<DBusPlaybackStatusChangedSignal> playback_status_changed;
257  std::shared_ptr<DBusVideoDimensionChangedSignal> video_dimension_changed;
258  std::shared_ptr<DBusErrorSignal> error;
259  } dbus;
260  } signals;
261 };
262 
264  const std::shared_ptr<Service>& parent,
265  const std::shared_ptr<core::dbus::Object>& object)
266  : d(new Private{parent, object})
267 {
268 }
269 
271 {
272 }
273 
274 std::shared_ptr<media::TrackList> media::PlayerStub::track_list()
275 {
276  if (!d->track_list)
277  {
278  d->track_list = std::make_shared<media::TrackListStub>(
279  shared_from_this(),
280  dbus::types::ObjectPath(d->object->path().as_string() + "/TrackList"));
281  }
282  return d->track_list;
283 }
284 
286 {
287  auto op = d->object->invoke_method_synchronously<mpris::Player::Key, media::Player::PlayerKey>();
288 
289  return op.value();
290 }
291 
293 {
294  auto op = d->object->invoke_method_synchronously<mpris::Player::OpenUri, bool>(uri);
295 
296  return op.value();
297 }
298 
299 bool media::PlayerStub::open_uri(const Track::UriType& uri, const Player::HeadersType& headers)
300 {
301  auto op = d->object->invoke_method_synchronously<mpris::Player::OpenUriExtended, bool>(uri, headers);
302 
303  return op.value();
304 }
305 
306 void media::PlayerStub::create_video_sink(uint32_t texture_id)
307 {
308  auto op = d->object->invoke_method_synchronously<mpris::Player::CreateVideoSink, void>(texture_id);
309  d->texture_id = texture_id;
310  d->get_gl_consumer();
311 
312  if (op.is_error())
313  throw std::runtime_error("Problem creating new video sink instance on remote object");
314 }
315 
317 {
318  return d->glc_wrapper;
319 }
320 
322 {
323  auto op = d->object->invoke_method_synchronously<mpris::Player::Next, void>();
324 
325  if (op.is_error())
326  throw std::runtime_error("Problem switching to next track on remote object");
327 }
328 
330 {
331  auto op = d->object->invoke_method_synchronously<mpris::Player::Previous, void>();
332 
333  if (op.is_error())
334  throw std::runtime_error("Problem switching to previous track on remote object");
335 }
336 
338 {
339  auto op = d->object->invoke_method_synchronously<mpris::Player::Play, void>();
340 
341  if (op.is_error())
342  throw std::runtime_error("Problem starting playback on remote object");
343 }
344 
346 {
347  auto op = d->object->invoke_method_synchronously<mpris::Player::Pause, void>();
348 
349  if (op.is_error())
350  throw std::runtime_error("Problem pausing playback on remote object");
351 }
352 
353 void media::PlayerStub::seek_to(const std::chrono::microseconds& offset)
354 {
355  auto op = d->object->invoke_method_synchronously<mpris::Player::Seek, void, uint64_t>(offset.count());
356 
357  if (op.is_error())
358  throw std::runtime_error("Problem seeking on remote object");
359 }
360 
362 {
363  auto op = d->object->invoke_method_synchronously<mpris::Player::Stop, void>();
364 
365  if (op.is_error())
366  throw std::runtime_error("Problem stopping playback on remote object");
367 }
368 
370 {
371  d->set_frame_available_cb(cb, context);
372 }
373 
375 {
376  d->signals.set_playback_complete_cb(cb, context);
377 }
378 
379 const core::Property<bool>& media::PlayerStub::can_play() const
380 {
381  return *d->properties.can_play;
382 }
383 
384 const core::Property<bool>& media::PlayerStub::can_pause() const
385 {
386  return *d->properties.can_pause;
387 }
388 
389 const core::Property<bool>& media::PlayerStub::can_seek() const
390 {
391  return *d->properties.can_seek;
392 }
393 
394 const core::Property<bool>& media::PlayerStub::can_go_previous() const
395 {
396  return *d->properties.can_go_previous;
397 }
398 
399 const core::Property<bool>& media::PlayerStub::can_go_next() const
400 {
401  return *d->properties.can_go_next;
402 }
403 
404 const core::Property<bool>& media::PlayerStub::is_video_source() const
405 {
406  return *d->properties.is_video_source;
407 }
408 
409 const core::Property<bool>& media::PlayerStub::is_audio_source() const
410 {
411  return *d->properties.is_audio_source;
412 }
413 
414 const core::Property<media::Player::PlaybackStatus>& media::PlayerStub::playback_status() const
415 {
416  return *d->properties.playback_status;
417 }
418 
419 const core::Property<media::Player::LoopStatus>& media::PlayerStub::loop_status() const
420 {
421  return *d->properties.loop_status;
422 }
423 
424 const core::Property<media::Player::PlaybackRate>& media::PlayerStub::playback_rate() const
425 {
426  return *d->properties.playback_rate;
427 }
428 
429 const core::Property<bool>& media::PlayerStub::is_shuffle() const
430 {
431  return *d->properties.is_shuffle;
432 }
433 
434 const core::Property<media::Track::MetaData>& media::PlayerStub::meta_data_for_current_track() const
435 {
436  return *d->properties.meta_data_for_current_track;
437 }
438 
439 const core::Property<media::Player::Volume>& media::PlayerStub::volume() const
440 {
441  return *d->properties.volume;
442 }
443 
444 const core::Property<int64_t>& media::PlayerStub::position() const
445 {
446  return *d->properties.position;
447 }
448 
449 const core::Property<int64_t>& media::PlayerStub::duration() const
450 {
451  return *d->properties.duration;
452 }
453 
454 const core::Property<media::Player::AudioStreamRole>& media::PlayerStub::audio_stream_role() const
455 {
456  return *d->properties.audio_role;
457 }
458 
459 const core::Property<media::Player::Orientation>& media::PlayerStub::orientation() const
460 {
461  return *d->properties.orientation;
462 }
463 
464 const core::Property<media::Player::Lifetime>& media::PlayerStub::lifetime() const
465 {
466  return *d->properties.lifetime;
467 }
468 
469 const core::Property<media::Player::PlaybackRate>& media::PlayerStub::minimum_playback_rate() const
470 {
471  return *d->properties.minimum_playback_rate;
472 }
473 
474 const core::Property<media::Player::PlaybackRate>& media::PlayerStub::maximum_playback_rate() const
475 {
476  return *d->properties.maximum_playback_rate;
477 }
478 
479 core::Property<media::Player::LoopStatus>& media::PlayerStub::loop_status()
480 {
481  return *d->properties.loop_status;
482 }
483 
484 core::Property<media::Player::PlaybackRate>& media::PlayerStub::playback_rate()
485 {
486  return *d->properties.playback_rate;
487 }
488 
489 core::Property<bool>& media::PlayerStub::is_shuffle()
490 {
491  return *d->properties.is_shuffle;
492 }
493 
494 core::Property<media::Player::Volume>& media::PlayerStub::volume()
495 {
496  return *d->properties.volume;
497 }
498 
499 core::Property<media::Player::AudioStreamRole>& media::PlayerStub::audio_stream_role()
500 {
501  return *d->properties.audio_role;
502 }
503 
504 core::Property<media::Player::Lifetime>& media::PlayerStub::lifetime()
505 {
506  return *d->properties.lifetime;
507 }
508 
509 const core::Signal<int64_t>& media::PlayerStub::seeked_to() const
510 {
511  return d->signals.seeked_to;
512 }
513 
514 const core::Signal<void>& media::PlayerStub::end_of_stream() const
515 {
516  return d->signals.end_of_stream;
517 }
518 
519 core::Signal<media::Player::PlaybackStatus>& media::PlayerStub::playback_status_changed()
520 {
521  return d->signals.playback_status_changed;
522 }
523 
524 const core::Signal<uint64_t>& media::PlayerStub::video_dimension_changed() const
525 {
526  return d->signals.video_dimension_changed;
527 }
528 
529 const core::Signal<media::Player::Error>& media::PlayerStub::error() const
530 {
531  return d->signals.error;
532 }
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)
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
core::dbus::Signal< mpris::Player::Signals::Error, mpris::Player::Signals::Error::ArgumentType > DBusErrorSignal
GLConsumerWrapperHybris glc_wrapper
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
void(* FrameAvailableCb)(void *context)
Definition: player.h:49
std::shared_ptr< DBusErrorSignal > error
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
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
void(* PlaybackCompleteCb)(void *context)
Definition: player.h:50
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
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, const std::shared_ptr< DBusErrorSignal > &e)
virtual const core::Property< Lifetime > & lifetime() const
virtual PlayerKey key() const
#define UNUSED
Definition: player_stub.cpp:41
core::Signal< media::Player::Error > error
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 const core::Signal< Error > & error() const
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