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>
23 
24 #include "codec.h"
25 #include "player_stub.h"
26 #include "player_traits.h"
27 #include "property_stub.h"
28 #include "the_session_bus.h"
29 #include "track_list_stub.h"
30 
31 #include "mpris/player.h"
32 
33 #include <core/dbus/property.h>
34 #include <core/dbus/types/object_path.h>
35 
36 #include <limits>
37 
38 #define UNUSED __attribute__((unused))
39 
40 namespace dbus = core::dbus;
41 namespace media = core::ubuntu::media;
42 
44 {
45  Private(const std::shared_ptr<Service>& parent,
46  const std::shared_ptr<core::dbus::Object>& object
47  ) : parent(parent),
48  object(object),
49  key(object->invoke_method_synchronously<mpris::Player::Key, media::Player::PlayerKey>().value()),
52  {
53  // Link the properties from the server side to the client side over the bus
54  object->get_property<mpris::Player::Properties::CanPlay>(),
55  object->get_property<mpris::Player::Properties::CanPause>(),
56  object->get_property<mpris::Player::Properties::CanSeek>(),
57  object->get_property<mpris::Player::Properties::CanControl>(),
58  object->get_property<mpris::Player::Properties::CanGoNext>(),
59  object->get_property<mpris::Player::Properties::CanGoPrevious>(),
60  object->get_property<mpris::Player::Properties::IsVideoSource>(),
61  object->get_property<mpris::Player::Properties::IsAudioSource>(),
62  object->get_property<mpris::Player::Properties::TypedPlaybackStatus>(),
63  object->get_property<mpris::Player::Properties::TypedLoopStatus>(),
64  object->get_property<mpris::Player::Properties::PlaybackRate>(),
65  object->get_property<mpris::Player::Properties::Shuffle>(),
66  object->get_property<mpris::Player::Properties::TypedMetaData>(),
67  object->get_property<mpris::Player::Properties::Volume>(),
68  object->get_property<mpris::Player::Properties::Position>(),
69  object->get_property<mpris::Player::Properties::Duration>(),
70  object->get_property<mpris::Player::Properties::AudioStreamRole>(),
71  object->get_property<mpris::Player::Properties::Orientation>(),
72  object->get_property<mpris::Player::Properties::Lifetime>(),
73  object->get_property<mpris::Player::Properties::MinimumRate>(),
74  object->get_property<mpris::Player::Properties::MaximumRate>()
75  },
76  signals
77  {
78  object->get_signal<mpris::Player::Signals::Seeked>(),
79  object->get_signal<mpris::Player::Signals::AboutToFinish>(),
80  object->get_signal<mpris::Player::Signals::EndOfStream>(),
81  object->get_signal<mpris::Player::Signals::PlaybackStatusChanged>(),
82  object->get_signal<mpris::Player::Signals::VideoDimensionChanged>(),
83  object->get_signal<mpris::Player::Signals::Error>()
84  }
85  {
86  }
87 
89  {
90  }
91 
92  std::shared_ptr<Service> parent;
93  std::shared_ptr<TrackList> track_list;
94  dbus::Object::Ptr object;
97  struct
98  {
99  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanPlay>> can_play;
100  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanPause>> can_pause;
101  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanSeek>> can_seek;
102  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanControl>> can_control;
103  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanGoNext>> can_go_next;
104  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanGoPrevious>> can_go_previous;
105  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::IsVideoSource>> is_video_source;
106  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::IsAudioSource>> is_audio_source;
107 
108  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::TypedPlaybackStatus>> playback_status;
109  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::TypedLoopStatus>> loop_status;
110  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::PlaybackRate>> playback_rate;
111  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Shuffle>> is_shuffle;
112  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::TypedMetaData>> meta_data_for_current_track;
113  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Volume>> volume;
114  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Position>> position;
115  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Duration>> duration;
116  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::AudioStreamRole>> audio_role;
117  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Orientation>> orientation;
118  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::Lifetime>> lifetime;
119  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MinimumRate>> minimum_playback_rate;
120  std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MaximumRate>> maximum_playback_rate;
121  } properties;
122 
123  struct Signals
124  {
125  typedef core::dbus::Signal<mpris::Player::Signals::Seeked, mpris::Player::Signals::Seeked::ArgumentType> DBusSeekedToSignal;
126  typedef core::dbus::Signal<mpris::Player::Signals::AboutToFinish, mpris::Player::Signals::AboutToFinish::ArgumentType> DBusAboutToFinishSignal;
127  typedef core::dbus::Signal<mpris::Player::Signals::EndOfStream, mpris::Player::Signals::EndOfStream::ArgumentType> DBusEndOfStreamSignal;
128  typedef core::dbus::Signal<mpris::Player::Signals::PlaybackStatusChanged, mpris::Player::Signals::PlaybackStatusChanged::ArgumentType> DBusPlaybackStatusChangedSignal;
129  typedef core::dbus::Signal<mpris::Player::Signals::VideoDimensionChanged, mpris::Player::Signals::VideoDimensionChanged::ArgumentType> DBusVideoDimensionChangedSignal;
130  typedef core::dbus::Signal<mpris::Player::Signals::Error, mpris::Player::Signals::Error::ArgumentType> DBusErrorSignal;
131 
132  Signals(const std::shared_ptr<DBusSeekedToSignal>& seeked,
133  const std::shared_ptr<DBusAboutToFinishSignal>& atf,
134  const std::shared_ptr<DBusEndOfStreamSignal>& eos,
135  const std::shared_ptr<DBusPlaybackStatusChangedSignal>& status,
136  const std::shared_ptr<DBusVideoDimensionChangedSignal>& d,
137  const std::shared_ptr<DBusErrorSignal>& e)
138  : seeked_to(),
139  about_to_finish(),
140  end_of_stream(),
143  error(),
144  dbus
145  {
146  seeked,
147  atf,
148  eos,
149  status,
150  d,
151  e
152  }
153  {
154  dbus.seeked_to->connect([this](std::uint64_t value)
155  {
156  std::cout << "seeked_to signal arrived via the bus." << std::endl;
157  seeked_to(value);
158  });
159 
160  dbus.about_to_finish->connect([this]()
161  {
162  std::cout << "AboutToFinish signal arrived via the bus." << std::endl;
163  about_to_finish();
164  });
165 
166  dbus.end_of_stream->connect([this]()
167  {
168  std::cout << "EndOfStream signal arrived via the bus." << std::endl;
169  end_of_stream();
170  });
171 
172  dbus.playback_status_changed->connect([this](const media::Player::PlaybackStatus& status)
173  {
174  std::cout << "PlaybackStatusChanged signal arrived via the bus." << std::endl;
175  playback_status_changed(status);
176  });
177 
178  dbus.video_dimension_changed->connect([this](const media::video::Dimensions dimensions)
179  {
180  std::cout << "VideoDimensionChanged signal arrived via the bus." << std::endl;
181  video_dimension_changed(dimensions);
182  });
183 
184  dbus.error->connect([this](const media::Player::Error& e)
185  {
186  std::cout << "Error signal arrived via the bus (Error: " << e << ")" << std::endl;
187  error(e);
188  });
189  }
190 
191  core::Signal<int64_t> seeked_to;
192  core::Signal<void> about_to_finish;
193  core::Signal<void> end_of_stream;
194  core::Signal<media::Player::PlaybackStatus> playback_status_changed;
195  core::Signal<media::video::Dimensions> video_dimension_changed;
196  core::Signal<media::Player::Error> error;
197 
198  struct DBus
199  {
200  std::shared_ptr<DBusSeekedToSignal> seeked_to;
201  std::shared_ptr<DBusAboutToFinishSignal> about_to_finish;
202  std::shared_ptr<DBusEndOfStreamSignal> end_of_stream;
203  std::shared_ptr<DBusPlaybackStatusChangedSignal> playback_status_changed;
204  std::shared_ptr<DBusVideoDimensionChangedSignal> video_dimension_changed;
205  std::shared_ptr<DBusErrorSignal> error;
206  } dbus;
207  } signals;
208 };
209 
211  const std::shared_ptr<Service>& parent,
212  const std::shared_ptr<core::dbus::Object>& object)
213  : d(new Private{parent, object})
214 {
215 }
216 
218 {
219 }
220 
221 std::shared_ptr<media::TrackList> media::PlayerStub::track_list()
222 {
223  if (!d->track_list)
224  {
225  d->track_list = std::make_shared<media::TrackListStub>(
226  shared_from_this(),
227  dbus::types::ObjectPath(d->object->path().as_string() + "/TrackList"));
228  }
229  return d->track_list;
230 }
231 
233 {
234  return d->key;
235 }
236 
238 {
239  auto op = d->object->transact_method<mpris::Player::OpenUri, bool>(uri);
240 
241  return op.value();
242 }
243 
244 
245 bool media::PlayerStub::open_uri(const Track::UriType& uri, const Player::HeadersType& headers)
246 {
247  auto op = d->object->transact_method<mpris::Player::OpenUriExtended, bool>(uri, headers);
248 
249  return op.value();
250 }
251 
252 media::video::Sink::Ptr media::PlayerStub::create_gl_texture_video_sink(std::uint32_t texture_id)
253 {
254  auto op = d->object->transact_method<mpris::Player::CreateVideoSink, void>(texture_id);
255 
256  if (op.is_error())
257  {
259  throw media::Player::Errors::OutOfProcessBufferStreamingNotSupported{};
260  else
261  throw std::runtime_error{op.error().print()};
262  }
263 
264  return d->sink_factory(texture_id);
265 }
266 
268 {
269  auto op = d->object->transact_method<mpris::Player::Next, void>();
270 
271  if (op.is_error())
272  throw std::runtime_error("Problem switching to next track on remote object");
273 }
274 
276 {
277  auto op = d->object->transact_method<mpris::Player::Previous, void>();
278 
279  if (op.is_error())
280  throw std::runtime_error("Problem switching to previous track on remote object");
281 }
282 
284 {
285  auto op = d->object->transact_method<mpris::Player::Play, void>();
286 
287  if (op.is_error())
288  throw std::runtime_error("Problem starting playback on remote object");
289 }
290 
292 {
293  auto op = d->object->transact_method<mpris::Player::Pause, void>();
294 
295  if (op.is_error())
296  throw std::runtime_error("Problem pausing playback on remote object");
297 }
298 
299 void media::PlayerStub::seek_to(const std::chrono::microseconds& offset)
300 {
301  auto op = d->object->transact_method<mpris::Player::Seek, void, uint64_t>(offset.count());
302 
303  if (op.is_error())
304  throw std::runtime_error("Problem seeking on remote object");
305 }
306 
308 {
309  auto op = d->object->transact_method<mpris::Player::Stop, void>();
310 
311  if (op.is_error())
312  throw std::runtime_error("Problem stopping playback on remote object");
313 }
314 
315 const core::Property<bool>& media::PlayerStub::can_play() const
316 {
317  return *d->properties.can_play;
318 }
319 
320 const core::Property<bool>& media::PlayerStub::can_pause() const
321 {
322  return *d->properties.can_pause;
323 }
324 
325 const core::Property<bool>& media::PlayerStub::can_seek() const
326 {
327  return *d->properties.can_seek;
328 }
329 
330 const core::Property<bool>& media::PlayerStub::can_go_previous() const
331 {
332  return *d->properties.can_go_previous;
333 }
334 
335 const core::Property<bool>& media::PlayerStub::can_go_next() const
336 {
337  return *d->properties.can_go_next;
338 }
339 
340 const core::Property<bool>& media::PlayerStub::is_video_source() const
341 {
342  return *d->properties.is_video_source;
343 }
344 
345 const core::Property<bool>& media::PlayerStub::is_audio_source() const
346 {
347  return *d->properties.is_audio_source;
348 }
349 
350 const core::Property<media::Player::PlaybackStatus>& media::PlayerStub::playback_status() const
351 {
352  return *d->properties.playback_status;
353 }
354 
355 const core::Property<media::Player::LoopStatus>& media::PlayerStub::loop_status() const
356 {
357  return *d->properties.loop_status;
358 }
359 
360 const core::Property<media::Player::PlaybackRate>& media::PlayerStub::playback_rate() const
361 {
362  return *d->properties.playback_rate;
363 }
364 
365 const core::Property<bool>& media::PlayerStub::is_shuffle() const
366 {
367  return *d->properties.is_shuffle;
368 }
369 
370 const core::Property<media::Track::MetaData>& media::PlayerStub::meta_data_for_current_track() const
371 {
372  return *d->properties.meta_data_for_current_track;
373 }
374 
375 const core::Property<media::Player::Volume>& media::PlayerStub::volume() const
376 {
377  return *d->properties.volume;
378 }
379 
380 const core::Property<int64_t>& media::PlayerStub::position() const
381 {
382  return *d->properties.position;
383 }
384 
385 const core::Property<int64_t>& media::PlayerStub::duration() const
386 {
387  return *d->properties.duration;
388 }
389 
390 const core::Property<media::Player::AudioStreamRole>& media::PlayerStub::audio_stream_role() const
391 {
392  return *d->properties.audio_role;
393 }
394 
395 const core::Property<media::Player::Orientation>& media::PlayerStub::orientation() const
396 {
397  return *d->properties.orientation;
398 }
399 
400 const core::Property<media::Player::Lifetime>& media::PlayerStub::lifetime() const
401 {
402  return *d->properties.lifetime;
403 }
404 
405 const core::Property<media::Player::PlaybackRate>& media::PlayerStub::minimum_playback_rate() const
406 {
407  return *d->properties.minimum_playback_rate;
408 }
409 
410 const core::Property<media::Player::PlaybackRate>& media::PlayerStub::maximum_playback_rate() const
411 {
412  return *d->properties.maximum_playback_rate;
413 }
414 
415 core::Property<media::Player::LoopStatus>& media::PlayerStub::loop_status()
416 {
417  return *d->properties.loop_status;
418 }
419 
420 core::Property<media::Player::PlaybackRate>& media::PlayerStub::playback_rate()
421 {
422  return *d->properties.playback_rate;
423 }
424 
425 core::Property<bool>& media::PlayerStub::is_shuffle()
426 {
427  return *d->properties.is_shuffle;
428 }
429 
430 core::Property<media::Player::Volume>& media::PlayerStub::volume()
431 {
432  return *d->properties.volume;
433 }
434 
435 core::Property<media::Player::AudioStreamRole>& media::PlayerStub::audio_stream_role()
436 {
437  return *d->properties.audio_role;
438 }
439 
440 core::Property<media::Player::Lifetime>& media::PlayerStub::lifetime()
441 {
442  return *d->properties.lifetime;
443 }
444 
445 const core::Signal<int64_t>& media::PlayerStub::seeked_to() const
446 {
447  return d->signals.seeked_to;
448 }
449 
450 const core::Signal<void>& media::PlayerStub::about_to_finish() const
451 {
452  return d->signals.about_to_finish;
453 }
454 
455 const core::Signal<void>& media::PlayerStub::end_of_stream() const
456 {
457  return d->signals.end_of_stream;
458 }
459 
460 core::Signal<media::Player::PlaybackStatus>& media::PlayerStub::playback_status_changed()
461 {
462  return d->signals.playback_status_changed;
463 }
464 
465 const core::Signal<media::video::Dimensions>& media::PlayerStub::video_dimension_changed() const
466 {
467  return d->signals.video_dimension_changed;
468 }
469 
470 const core::Signal<media::Player::Error>& media::PlayerStub::error() const
471 {
472  return d->signals.error;
473 }
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::CanPlay > > can_play
Definition: player_stub.cpp:99
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::CanControl > > can_control
std::shared_ptr< DBusEndOfStreamSignal > end_of_stream
std::shared_ptr< DBusVideoDimensionChangedSignal > video_dimension_changed
virtual video::Sink::Ptr create_gl_texture_video_sink(std::uint32_t texture_id)
SinkFactory make_platform_default_sink_factory(const Player::PlayerKey &key)
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::IsAudioSource > > is_audio_source
virtual const core::Property< int64_t > & position() const
std::tuple< Height, Width > Dimensions
Height and Width of a video.
Definition: dimensions.h:139
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< void > & end_of_stream() const
core::Signal< void > end_of_stream
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::Lifetime > > lifetime
dbus::Object::Ptr object
Definition: player_stub.cpp:94
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:48
std::shared_ptr< Service > parent
Definition: player_stub.cpp:92
core::dbus::Signal< mpris::Player::Signals::VideoDimensionChanged, mpris::Player::Signals::VideoDimensionChanged::ArgumentType > DBusVideoDimensionChangedSignal
core::Signal< void > about_to_finish
virtual const core::Property< bool > & can_pause() const
core::Signal< media::video::Dimensions > video_dimension_changed
core::dbus::Signal< mpris::Player::Signals::Error, mpris::Player::Signals::Error::ArgumentType > DBusErrorSignal
virtual const core::Signal< video::Dimensions > & video_dimension_changed() const
virtual const core::Property< Volume > & volume() const
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
std::shared_ptr< DBusErrorSignal > error
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::TypedLoopStatus > > loop_status
media::video::SinkFactory sink_factory
Definition: player_stub.cpp:96
std::shared_ptr< DBusAboutToFinishSignal > about_to_finish
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
core::dbus::Signal< mpris::Player::Signals::AboutToFinish, mpris::Player::Signals::AboutToFinish::ArgumentType > DBusAboutToFinishSignal
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::CanPause > > can_pause
Signals(const std::shared_ptr< DBusSeekedToSignal > &seeked, const std::shared_ptr< DBusAboutToFinishSignal > &atf, const std::shared_ptr< DBusEndOfStreamSignal > &eos, const std::shared_ptr< DBusPlaybackStatusChangedSignal > &status, const std::shared_ptr< DBusVideoDimensionChangedSignal > &d, const std::shared_ptr< DBusErrorSignal > &e)
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:45
std::function< Sink::Ptr(std::uint32_t)> SinkFactory
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::Shuffle > > is_shuffle
virtual const core::Signal< void > & about_to_finish() const
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
Definition: player_stub.cpp:93
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::CanSeek > > can_seek
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
core::Signal< media::Player::Error > error
virtual const core::Property< PlaybackRate > & minimum_playback_rate() const
virtual const core::Property< bool > & can_seek() const
virtual bool open_uri(const Track::UriType &uri)
std::string UriType
Definition: track.h:40
std::shared_ptr< core::dbus::Property< mpris::Player::Properties::Position > > position
core::Signal< int64_t > seeked_to
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
struct media::PlayerStub::Private::@20 properties
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
media::Player::PlayerKey key
Definition: player_stub.cpp:95