Music Hub  ..
A session-wide music playback service
engine.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 <stdio.h>
21 #include <stdlib.h>
22 
23 #include "bus.h"
24 #include "engine.h"
25 #include "meta_data_extractor.h"
26 #include "playbin.h"
27 
28 #include <cassert>
29 
30 namespace media = core::ubuntu::media;
31 
32 using namespace std;
33 
34 namespace gstreamer
35 {
36 struct Init
37 {
38  Init()
39  {
40  gst_init(nullptr, nullptr);
41  }
42 
44  {
45  gst_deinit();
46  }
47 } init;
48 }
49 
51 {
53  {
54  if (state.new_state == GST_STATE_PLAYING)
55  return media::Player::PlaybackStatus::playing;
56  else if (state.new_state == GST_STATE_PAUSED)
57  return media::Player::PlaybackStatus::paused;
58  else if (state.new_state == GST_STATE_READY)
59  return media::Player::PlaybackStatus::ready;
60  else if (state.new_state == GST_STATE_NULL)
61  return media::Player::PlaybackStatus::null;
62  else
63  return media::Player::PlaybackStatus::stopped;
64  }
65 
66  void on_playbin_state_changed(const std::pair<gstreamer::Bus::Message::Detail::StateChanged,std::string>& p)
67  {
68  if (p.second == "playbin")
69  {
70  std::cout << "State changed on playbin: " << p.first.new_state << std::endl;
71  playback_status_changed(gst_state_to_player_status(p.first));
72  }
73  }
74 
75  // Converts from a GStreamer GError to a media::Player:Error enum
77  {
78  media::Player::Error ret_error = media::Player::Error::no_error;
79 
80  if (g_strcmp0(g_quark_to_string(ewi.error->domain), "gst-core-error-quark") == 0)
81  {
82  switch (ewi.error->code)
83  {
84  case GST_CORE_ERROR_FAILED:
85  std::cerr << "** Encountered a GST_CORE_ERROR_FAILED" << std::endl;
86  ret_error = media::Player::Error::resource_error;
87  break;
88  case GST_CORE_ERROR_NEGOTIATION:
89  std::cerr << "** Encountered a GST_CORE_ERROR_NEGOTIATION" << std::endl;
90  ret_error = media::Player::Error::resource_error;
91  break;
92  case GST_CORE_ERROR_MISSING_PLUGIN:
93  std::cerr << "** Encountered a GST_CORE_ERROR_MISSING_PLUGIN" << std::endl;
94  ret_error = media::Player::Error::format_error;
95  break;
96  default:
97  std::cerr << "** Encountered an unhandled core error: '"
98  << ewi.debug << "' (code: " << ewi.error->code << ")" << std::endl;
99  ret_error = media::Player::Error::no_error;
100  break;
101  }
102  }
103  else if (g_strcmp0(g_quark_to_string(ewi.error->domain), "gst-resource-error-quark") == 0)
104  {
105  switch (ewi.error->code)
106  {
107  case GST_RESOURCE_ERROR_FAILED:
108  std::cerr << "** Encountered a GST_RESOURCE_ERROR_FAILED" << std::endl;
109  ret_error = media::Player::Error::resource_error;
110  break;
111  case GST_RESOURCE_ERROR_NOT_FOUND:
112  std::cerr << "** Encountered a GST_RESOURCE_ERROR_NOT_FOUND" << std::endl;
113  ret_error = media::Player::Error::resource_error;
114  break;
115  case GST_RESOURCE_ERROR_OPEN_READ:
116  std::cerr << "** Encountered a GST_RESOURCE_ERROR_OPEN_READ" << std::endl;
117  ret_error = media::Player::Error::resource_error;
118  break;
119  case GST_RESOURCE_ERROR_OPEN_WRITE:
120  std::cerr << "** Encountered a GST_RESOURCE_ERROR_OPEN_WRITE" << std::endl;
121  ret_error = media::Player::Error::resource_error;
122  break;
123  case GST_RESOURCE_ERROR_READ:
124  std::cerr << "** Encountered a GST_RESOURCE_ERROR_READ" << std::endl;
125  ret_error = media::Player::Error::resource_error;
126  break;
127  case GST_RESOURCE_ERROR_WRITE:
128  std::cerr << "** Encountered a GST_RESOURCE_ERROR_WRITE" << std::endl;
129  ret_error = media::Player::Error::resource_error;
130  break;
131  case GST_RESOURCE_ERROR_NOT_AUTHORIZED:
132  std::cerr << "** Encountered a GST_RESOURCE_ERROR_NOT_AUTHORIZED" << std::endl;
133  ret_error = media::Player::Error::access_denied_error;
134  break;
135  default:
136  std::cerr << "** Encountered an unhandled resource error: '"
137  << ewi.debug << "' (code: " << ewi.error->code << ")" << std::endl;
138  ret_error = media::Player::Error::no_error;
139  break;
140  }
141  }
142  else if (g_strcmp0(g_quark_to_string(ewi.error->domain), "gst-stream-error-quark") == 0)
143  {
144  switch (ewi.error->code)
145  {
146  case GST_STREAM_ERROR_FAILED:
147  std::cerr << "** Encountered a GST_STREAM_ERROR_FAILED" << std::endl;
148  ret_error = media::Player::Error::resource_error;
149  break;
150  case GST_STREAM_ERROR_CODEC_NOT_FOUND:
151  std::cerr << "** Encountered a GST_STREAM_ERROR_CODEC_NOT_FOUND" << std::endl;
152  ret_error = media::Player::Error::format_error;
153  break;
154  case GST_STREAM_ERROR_DECODE:
155  std::cerr << "** Encountered a GST_STREAM_ERROR_DECODE" << std::endl;
156  ret_error = media::Player::Error::format_error;
157  break;
158  default:
159  std::cerr << "** Encountered an unhandled stream error: '"
160  << ewi.debug << "' (code: " << ewi.error->code << ")" << std::endl;
161  ret_error = media::Player::Error::no_error;
162  break;
163  }
164  }
165 
166  std::cout << "Resetting playbin pipeline after unrecoverable error" << std::endl;
167  playbin.reset();
168  return ret_error;
169  }
170 
172  {
173  const media::Player::Error e = from_gst_errorwarning(ewi);
174  if (e != media::Player::Error::no_error)
175  error(e);
176  }
177 
179  {
180  const media::Player::Error e = from_gst_errorwarning(ewi);
181  if (e != media::Player::Error::no_error)
182  error(e);
183  }
184 
186  {
187  std::cerr << "Got a playbin info message (no action taken): " << ewi.debug << std::endl;
188  }
189 
191  {
192  media::Track::MetaData md;
194  track_meta_data.set(std::make_tuple(playbin.uri(), md));
195  }
196 
197  void on_volume_changed(const media::Engine::Volume& new_volume)
198  {
199  playbin.set_volume(new_volume.value);
200  }
201 
203  {
204  playbin.set_audio_stream_role(new_audio_role);
205  }
206 
208  {
209  // Update the local orientation Property, which should then update the Player
210  // orientation Property
211  orientation.set(o);
212  }
213 
215  {
216  playbin.set_lifetime(lifetime);
217  }
218 
220  {
221  state = Engine::State::ready;
222  about_to_finish();
223  }
224 
225  void on_seeked_to(uint64_t value)
226  {
227  seeked_to(value);
228  }
229 
231  {
232  client_disconnected();
233  }
234 
236  {
237  end_of_stream();
238  }
239 
241  {
242  video_dimension_changed(dimensions);
243  }
244 
246  : meta_data_extractor(new gstreamer::MetaDataExtractor()),
247  volume(media::Engine::Volume(1.)),
248  orientation(media::Player::Orientation::rotate0),
249  is_video_source(false),
250  is_audio_source(false),
251  about_to_finish_connection(
252  playbin.signals.about_to_finish.connect(
253  std::bind(
254  &Private::on_about_to_finish,
255  this))),
256  on_state_changed_connection(
257  playbin.signals.on_state_changed.connect(
258  std::bind(
259  &Private::on_playbin_state_changed,
260  this,
261  std::placeholders::_1))),
262  on_error_connection(
263  playbin.signals.on_error.connect(
264  std::bind(
265  &Private::on_playbin_error,
266  this,
267  std::placeholders::_1))),
268  on_warning_connection(
269  playbin.signals.on_warning.connect(
270  std::bind(
271  &Private::on_playbin_warning,
272  this,
273  std::placeholders::_1))),
274  on_info_connection(
275  playbin.signals.on_info.connect(
276  std::bind(
277  &Private::on_playbin_info,
278  this,
279  std::placeholders::_1))),
280  on_tag_available_connection(
281  playbin.signals.on_tag_available.connect(
282  std::bind(
283  &Private::on_tag_available,
284  this,
285  std::placeholders::_1))),
286  on_volume_changed_connection(
287  volume.changed().connect(
288  std::bind(
289  &Private::on_volume_changed,
290  this,
291  std::placeholders::_1))),
292  on_audio_stream_role_changed_connection(
293  audio_role.changed().connect(
294  std::bind(
295  &Private::on_audio_stream_role_changed,
296  this,
297  std::placeholders::_1))),
298  on_orientation_changed_connection(
299  playbin.signals.on_orientation_changed.connect(
300  std::bind(
301  &Private::on_orientation_changed,
302  this,
303  std::placeholders::_1))),
304  on_lifetime_changed_connection(
305  lifetime.changed().connect(
306  std::bind(
307  &Private::on_lifetime_changed,
308  this,
309  std::placeholders::_1))),
310  on_seeked_to_connection(
311  playbin.signals.on_seeked_to.connect(
312  std::bind(
313  &Private::on_seeked_to,
314  this,
315  std::placeholders::_1))),
316  client_disconnected_connection(
317  playbin.signals.client_disconnected.connect(
318  std::bind(
319  &Private::on_client_disconnected,
320  this))),
321  on_end_of_stream_connection(
322  playbin.signals.on_end_of_stream.connect(
323  std::bind(
324  &Private::on_end_of_stream,
325  this))),
326  on_video_dimension_changed_connection(
327  playbin.signals.on_video_dimensions_changed.connect(
328  std::bind(
329  &Private::on_video_dimension_changed,
330  this,
331  std::placeholders::_1)))
332  {
333  }
334 
335  // Ensure the playbin is the last item destroyed
336  // otherwise properties could try to access a dead playbin object
338 
339  std::shared_ptr<Engine::MetaDataExtractor> meta_data_extractor;
340  core::Property<Engine::State> state;
341  core::Property<std::tuple<media::Track::UriType, media::Track::MetaData>> track_meta_data;
342  core::Property<uint64_t> position;
343  core::Property<uint64_t> duration;
344  core::Property<media::Engine::Volume> volume;
345  core::Property<media::Player::AudioStreamRole> audio_role;
346  core::Property<media::Player::Orientation> orientation;
347  core::Property<media::Player::Lifetime> lifetime;
348  core::Property<bool> is_video_source;
349  core::Property<bool> is_audio_source;
350 
351  core::ScopedConnection about_to_finish_connection;
352  core::ScopedConnection on_state_changed_connection;
353  core::ScopedConnection on_error_connection;
354  core::ScopedConnection on_warning_connection;
355  core::ScopedConnection on_info_connection;
356  core::ScopedConnection on_tag_available_connection;
357  core::ScopedConnection on_volume_changed_connection;
359  core::ScopedConnection on_orientation_changed_connection;
360  core::ScopedConnection on_lifetime_changed_connection;
361  core::ScopedConnection on_seeked_to_connection;
362  core::ScopedConnection client_disconnected_connection;
363  core::ScopedConnection on_end_of_stream_connection;
365 
366  core::Signal<void> about_to_finish;
367  core::Signal<uint64_t> seeked_to;
368  core::Signal<void> client_disconnected;
369  core::Signal<void> end_of_stream;
370  core::Signal<media::Player::PlaybackStatus> playback_status_changed;
371  core::Signal<core::ubuntu::media::video::Dimensions> video_dimension_changed;
372  core::Signal<media::Player::Error> error;
373 };
374 
376 {
377  cout << "Creating a new Engine instance in " << __PRETTY_FUNCTION__ << endl;
378  d->state = media::Engine::State::no_media;
379 }
380 
382 {
383  stop();
384  d->state = media::Engine::State::no_media;
385 }
386 
387 const std::shared_ptr<media::Engine::MetaDataExtractor>& gstreamer::Engine::meta_data_extractor() const
388 {
389  return d->meta_data_extractor;
390 }
391 
392 const core::Property<media::Engine::State>& gstreamer::Engine::state() const
393 {
394  return d->state;
395 }
396 
397 bool gstreamer::Engine::open_resource_for_uri(const media::Track::UriType& uri, bool do_pipeline_reset)
398 {
399  d->playbin.set_uri(uri, core::ubuntu::media::Player::HeadersType{}, do_pipeline_reset);
400  return true;
401 }
402 
404 {
405  d->playbin.set_uri(uri, headers);
406  return true;
407 }
408 
409 void gstreamer::Engine::create_video_sink(uint32_t texture_id)
410 {
411  d->playbin.create_video_sink(texture_id);
412 }
413 
415 {
416  auto result = d->playbin.set_state_and_wait(GST_STATE_PLAYING);
417 
418  if (result)
419  {
420  d->state = media::Engine::State::playing;
421  cout << __PRETTY_FUNCTION__ << endl;
422  cout << "Engine: playing uri: " << d->playbin.uri() << endl;
423  d->playback_status_changed(media::Player::PlaybackStatus::playing);
424  }
425 
426  return result;
427 }
428 
430 {
431  // No need to wait, and we can immediately return.
432  if (d->state == media::Engine::State::stopped)
433  return true;
434 
435  auto result = d->playbin.set_state_and_wait(GST_STATE_NULL);
436 
437  if (result)
438  {
439  d->state = media::Engine::State::stopped;
440  cout << __PRETTY_FUNCTION__ << endl;
441  d->playback_status_changed(media::Player::PlaybackStatus::stopped);
442  }
443 
444  return result;
445 }
446 
448 {
449  auto result = d->playbin.set_state_and_wait(GST_STATE_PAUSED);
450 
451  if (result)
452  {
453  d->state = media::Engine::State::paused;
454  cout << __PRETTY_FUNCTION__ << endl;
455  d->playback_status_changed(media::Player::PlaybackStatus::paused);
456  }
457 
458  return result;
459 }
460 
461 bool gstreamer::Engine::seek_to(const std::chrono::microseconds& ts)
462 {
463  return d->playbin.seek(ts);
464 }
465 
466 const core::Property<bool>& gstreamer::Engine::is_video_source() const
467 {
468  gstreamer::Playbin::MediaFileType type = d->playbin.media_file_type();
469  if (type == gstreamer::Playbin::MediaFileType::MEDIA_FILE_TYPE_VIDEO)
470  d->is_video_source.set(true);
471  else
472  d->is_video_source.set(false);
473 
474  return d->is_video_source;
475 }
476 
477 const core::Property<bool>& gstreamer::Engine::is_audio_source() const
478 {
479  gstreamer::Playbin::MediaFileType type = d->playbin.media_file_type();
480  if (type == gstreamer::Playbin::MediaFileType::MEDIA_FILE_TYPE_AUDIO)
481  d->is_audio_source.set(true);
482  else
483  d->is_audio_source.set(false);
484 
485  return d->is_audio_source;
486 }
487 
488 const core::Property<uint64_t>& gstreamer::Engine::position() const
489 {
490  d->position.set(d->playbin.position());
491  return d->position;
492 }
493 
494 const core::Property<uint64_t>& gstreamer::Engine::duration() const
495 {
496  d->duration.set(d->playbin.duration());
497  return d->duration;
498 }
499 
500 const core::Property<core::ubuntu::media::Engine::Volume>& gstreamer::Engine::volume() const
501 {
502  return d->volume;
503 }
504 
505 core::Property<core::ubuntu::media::Engine::Volume>& gstreamer::Engine::volume()
506 {
507  return d->volume;
508 }
509 
510 const core::Property<core::ubuntu::media::Player::AudioStreamRole>& gstreamer::Engine::audio_stream_role() const
511 {
512  return d->audio_role;
513 }
514 
515 const core::Property<core::ubuntu::media::Player::Lifetime>& gstreamer::Engine::lifetime() const
516 {
517  return d->lifetime;
518 }
519 
520 core::Property<core::ubuntu::media::Player::AudioStreamRole>& gstreamer::Engine::audio_stream_role()
521 {
522  return d->audio_role;
523 }
524 
525 const core::Property<core::ubuntu::media::Player::Orientation>& gstreamer::Engine::orientation() const
526 {
527  return d->orientation;
528 }
529 
530 core::Property<core::ubuntu::media::Player::Lifetime>& gstreamer::Engine::lifetime()
531 {
532  return d->lifetime;
533 }
534 
535 const core::Property<std::tuple<media::Track::UriType, media::Track::MetaData>>&
537 {
538  return d->track_meta_data;
539 }
540 
541 const core::Signal<void>& gstreamer::Engine::about_to_finish_signal() const
542 {
543  return d->about_to_finish;
544 }
545 
546 const core::Signal<uint64_t>& gstreamer::Engine::seeked_to_signal() const
547 {
548  return d->seeked_to;
549 }
550 
551 const core::Signal<void>& gstreamer::Engine::client_disconnected_signal() const
552 {
553  return d->client_disconnected;
554 }
555 
556 const core::Signal<void>& gstreamer::Engine::end_of_stream_signal() const
557 {
558  return d->end_of_stream;
559 }
560 
561 const core::Signal<media::Player::PlaybackStatus>& gstreamer::Engine::playback_status_changed_signal() const
562 {
563  return d->playback_status_changed;
564 }
565 
566 const core::Signal<core::ubuntu::media::video::Dimensions>& gstreamer::Engine::video_dimension_changed_signal() const
567 {
568  return d->video_dimension_changed;
569 }
570 
571 const core::Signal<core::ubuntu::media::Player::Error>& gstreamer::Engine::error_signal() const
572 {
573  return d->error;
574 }
575 
577 {
578  d->playbin.reset();
579 }
void on_tag_available(const gstreamer::Bus::Message::Detail::Tag &tag)
Definition: engine.cpp:190
core::ScopedConnection on_state_changed_connection
Definition: engine.cpp:352
core::ScopedConnection on_video_dimension_changed_connection
Definition: engine.cpp:364
core::Signal< core::ubuntu::media::video::Dimensions > video_dimension_changed
Definition: engine.cpp:371
const core::Property< core::ubuntu::media::Engine::Volume > & volume() const
Definition: engine.cpp:500
core::Property< bool > is_video_source
Definition: engine.cpp:348
const core::Signal< core::ubuntu::media::Player::PlaybackStatus > & playback_status_changed_signal() const
Definition: engine.cpp:561
const core::Property< core::ubuntu::media::Player::AudioStreamRole > & audio_stream_role() const
Definition: engine.cpp:510
std::tuple< Height, Width > Dimensions
Height and Width of a video.
Definition: dimensions.h:139
const core::Property< bool > & is_video_source() const
Definition: engine.cpp:466
const core::Signal< void > & client_disconnected_signal() const
Definition: engine.cpp:551
core::ScopedConnection on_info_connection
Definition: engine.cpp:355
core::Signal< void > end_of_stream
Definition: engine.cpp:369
Definition: bus.h:33
core::ScopedConnection on_lifetime_changed_connection
Definition: engine.cpp:360
void on_seeked_to(uint64_t value)
Definition: engine.cpp:225
void on_playbin_warning(const gstreamer::Bus::Message::Detail::ErrorWarningInfo &ewi)
Definition: engine.cpp:178
STL namespace.
const core::Property< State > & state() const
Definition: engine.cpp:392
const core::Property< core::ubuntu::media::Player::Lifetime > & lifetime() const
Definition: engine.cpp:515
core::ScopedConnection on_seeked_to_connection
Definition: engine.cpp:361
core::ScopedConnection on_end_of_stream_connection
Definition: engine.cpp:363
void on_orientation_changed(const media::Player::Orientation &o)
Definition: engine.cpp:207
core::Signal< media::Player::Error > error
Definition: engine.cpp:372
std::map< std::string, std::string > HeadersType
Definition: player.h:49
gstreamer::Playbin playbin
Definition: engine.cpp:337
bool seek_to(const std::chrono::microseconds &ts)
Definition: engine.cpp:461
core::ScopedConnection on_warning_connection
Definition: engine.cpp:354
bool open_resource_for_uri(const core::ubuntu::media::Track::UriType &uri, bool do_pipeline_reset)
const core::Signal< uint64_t > & seeked_to_signal() const
Definition: engine.cpp:546
struct gstreamer::Init init
void create_video_sink(uint32_t texture_id)
Definition: engine.cpp:409
const core::Property< std::tuple< core::ubuntu::media::Track::UriType, core::ubuntu::media::Track::MetaData > > & track_meta_data() const
Definition: engine.cpp:536
core::ScopedConnection client_disconnected_connection
Definition: engine.cpp:362
void on_playbin_error(const gstreamer::Bus::Message::Detail::ErrorWarningInfo &ewi)
Definition: engine.cpp:171
media::Player::Error from_gst_errorwarning(const gstreamer::Bus::Message::Detail::ErrorWarningInfo &ewi)
Definition: engine.cpp:76
const core::Property< bool > & is_audio_source() const
Definition: engine.cpp:477
void on_volume_changed(const media::Engine::Volume &new_volume)
Definition: engine.cpp:197
const core::Signal< core::ubuntu::media::Player::Error > & error_signal() const
Definition: engine.cpp:571
const core::Property< uint64_t > & duration() const
Definition: engine.cpp:494
core::ScopedConnection on_volume_changed_connection
Definition: engine.cpp:357
const core::Signal< void > & about_to_finish_signal() const
Definition: engine.cpp:541
core::Property< media::Player::Orientation > orientation
Definition: engine.cpp:346
core::Property< media::Player::AudioStreamRole > audio_role
Definition: engine.cpp:345
const core::Signal< void > & end_of_stream_signal() const
Definition: engine.cpp:556
const core::Signal< core::ubuntu::media::video::Dimensions > & video_dimension_changed_signal() const
Definition: engine.cpp:566
core::Signal< void > client_disconnected
Definition: engine.cpp:368
core::Signal< uint64_t > seeked_to
Definition: engine.cpp:367
void on_playbin_info(const gstreamer::Bus::Message::Detail::ErrorWarningInfo &ewi)
Definition: engine.cpp:185
core::ScopedConnection on_error_connection
Definition: engine.cpp:353
core::Property< media::Player::Lifetime > lifetime
Definition: engine.cpp:347
std::shared_ptr< Engine::MetaDataExtractor > meta_data_extractor
Definition: engine.cpp:339
static void on_tag_available(const gstreamer::Bus::Message::Detail::Tag &tag, core::ubuntu::media::Track::MetaData &md)
core::ScopedConnection on_tag_available_connection
Definition: engine.cpp:356
const std::shared_ptr< MetaDataExtractor > & meta_data_extractor() const
Definition: engine.cpp:387
core::Property< media::Engine::Volume > volume
Definition: engine.cpp:344
void on_playbin_state_changed(const std::pair< gstreamer::Bus::Message::Detail::StateChanged, std::string > &p)
Definition: engine.cpp:66
media::Player::PlaybackStatus gst_state_to_player_status(const gstreamer::Bus::Message::Detail::StateChanged &state)
Definition: engine.cpp:52
std::string UriType
Definition: track.h:40
core::ScopedConnection about_to_finish_connection
Definition: engine.cpp:351
core::Property< Engine::State > state
Definition: engine.cpp:340
const core::Property< core::ubuntu::media::Player::Orientation > & orientation() const
Definition: engine.cpp:525
core::Property< uint64_t > position
Definition: engine.cpp:342
core::Property< std::tuple< media::Track::UriType, media::Track::MetaData > > track_meta_data
Definition: engine.cpp:341
core::Signal< void > about_to_finish
Definition: engine.cpp:366
core::Signal< media::Player::PlaybackStatus > playback_status_changed
Definition: engine.cpp:370
const core::Property< uint64_t > & position() const
Definition: engine.cpp:488
core::ScopedConnection on_orientation_changed_connection
Definition: engine.cpp:359
void on_audio_stream_role_changed(const media::Player::AudioStreamRole &new_audio_role)
Definition: engine.cpp:202
void on_video_dimension_changed(const media::video::Dimensions &dimensions)
Definition: engine.cpp:240
void on_lifetime_changed(const media::Player::Lifetime &lifetime)
Definition: engine.cpp:214
core::Property< bool > is_audio_source
Definition: engine.cpp:349
core::Property< uint64_t > duration
Definition: engine.cpp:343
core::ScopedConnection on_audio_stream_role_changed_connection
Definition: engine.cpp:358