Music Hub  ..
A session-wide music playback service
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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 {
54  {
55  (void) state_change;
56  }
57 
59  {
60  media::Track::MetaData md;
62  track_meta_data.set(std::make_tuple(playbin.uri(), md));
63  }
64 
65  void on_volume_changed(const media::Engine::Volume& new_volume)
66  {
67  playbin.set_volume(new_volume.value);
68  }
69 
71  {
72  playbin.set_audio_stream_role(new_audio_role);
73  }
74 
76  {
77  // Update the local orientation Property, which should then update the Player
78  // orientation Property
79  orientation.set(o);
80  }
81 
83  {
84  playbin.set_lifetime(lifetime);
85  }
86 
88  {
89  state = Engine::State::ready;
90  about_to_finish();
91  }
92 
93  void on_seeked_to(uint64_t value)
94  {
95  seeked_to(value);
96  }
97 
99  {
100  client_disconnected();
101  }
102 
104  {
105  end_of_stream();
106  }
107 
108  void on_video_dimension_changed(uint32_t height, uint32_t width)
109  {
110  video_dimension_changed(height, width);
111  }
112 
114  : meta_data_extractor(new gstreamer::MetaDataExtractor()),
115  volume(media::Engine::Volume(1.)),
116  orientation(media::Player::Orientation::rotate0),
117  is_video_source(false),
118  is_audio_source(false),
119  about_to_finish_connection(
120  playbin.signals.about_to_finish.connect(
121  std::bind(
122  &Private::on_about_to_finish,
123  this))),
124  on_state_changed_connection(
125  playbin.signals.on_state_changed.connect(
126  std::bind(
127  &Private::on_playbin_state_changed,
128  this,
129  std::placeholders::_1))),
130  on_tag_available_connection(
131  playbin.signals.on_tag_available.connect(
132  std::bind(
133  &Private::on_tag_available,
134  this,
135  std::placeholders::_1))),
136  on_volume_changed_connection(
137  volume.changed().connect(
138  std::bind(
139  &Private::on_volume_changed,
140  this,
141  std::placeholders::_1))),
142  on_audio_stream_role_changed_connection(
143  audio_role.changed().connect(
144  std::bind(
145  &Private::on_audio_stream_role_changed,
146  this,
147  std::placeholders::_1))),
148  on_orientation_changed_connection(
149  playbin.signals.on_orientation_changed.connect(
150  std::bind(
151  &Private::on_orientation_changed,
152  this,
153  std::placeholders::_1))),
154  on_lifetime_changed_connection(
155  lifetime.changed().connect(
156  std::bind(
157  &Private::on_lifetime_changed,
158  this,
159  std::placeholders::_1))),
160  on_seeked_to_connection(
161  playbin.signals.on_seeked_to.connect(
162  std::bind(
163  &Private::on_seeked_to,
164  this,
165  std::placeholders::_1))),
166  client_disconnected_connection(
167  playbin.signals.client_disconnected.connect(
168  std::bind(
169  &Private::on_client_disconnected,
170  this))),
171  on_end_of_stream_connection(
172  playbin.signals.on_end_of_stream.connect(
173  std::bind(
174  &Private::on_end_of_stream,
175  this))),
176  on_video_dimension_changed_connection(
177  playbin.signals.on_add_frame_dimension.connect(
178  std::bind(
179  &Private::on_video_dimension_changed,
180  this,
181  std::placeholders::_1,
182  std::placeholders::_2)))
183  {
184  }
185 
186  // Ensure the playbin is the last item destroyed
187  // otherwise properties could try to access a dead playbin object
189 
190  std::shared_ptr<Engine::MetaDataExtractor> meta_data_extractor;
191  core::Property<Engine::State> state;
192  core::Property<std::tuple<media::Track::UriType, media::Track::MetaData>> track_meta_data;
193  core::Property<uint64_t> position;
194  core::Property<uint64_t> duration;
195  core::Property<media::Engine::Volume> volume;
196  core::Property<media::Player::AudioStreamRole> audio_role;
197  core::Property<media::Player::Orientation> orientation;
198  core::Property<media::Player::Lifetime> lifetime;
199  core::Property<bool> is_video_source;
200  core::Property<bool> is_audio_source;
201 
202  core::ScopedConnection about_to_finish_connection;
203  core::ScopedConnection on_state_changed_connection;
204  core::ScopedConnection on_tag_available_connection;
205  core::ScopedConnection on_volume_changed_connection;
207  core::ScopedConnection on_orientation_changed_connection;
208  core::ScopedConnection on_lifetime_changed_connection;
209  core::ScopedConnection on_seeked_to_connection;
210  core::ScopedConnection client_disconnected_connection;
211  core::ScopedConnection on_end_of_stream_connection;
213 
214  core::Signal<void> about_to_finish;
215  core::Signal<uint64_t> seeked_to;
216  core::Signal<void> client_disconnected;
217  core::Signal<void> end_of_stream;
218  core::Signal<media::Player::PlaybackStatus> playback_status_changed;
219  core::Signal<uint32_t, uint32_t> video_dimension_changed;
220 };
221 
223 {
224  cout << "Creating a new Engine instance in " << __PRETTY_FUNCTION__ << endl;
225  d->state = media::Engine::State::ready;
226 }
227 
229 {
230  stop();
231 }
232 
233 const std::shared_ptr<media::Engine::MetaDataExtractor>& gstreamer::Engine::meta_data_extractor() const
234 {
235  return d->meta_data_extractor;
236 }
237 
238 const core::Property<media::Engine::State>& gstreamer::Engine::state() const
239 {
240  return d->state;
241 }
242 
244 {
245  d->playbin.set_uri(uri);
246  return true;
247 }
248 
250 {
251  d->playbin.set_uri(uri, headers);
252  return true;
253 }
254 
255 void gstreamer::Engine::create_video_sink(uint32_t texture_id)
256 {
257  d->playbin.create_video_sink(texture_id);
258 }
259 
261 {
262  auto result = d->playbin.set_state_and_wait(GST_STATE_PLAYING);
263 
264  if (result)
265  {
266  d->state = media::Engine::State::playing;
267  cout << "play" << endl;
268  d->playback_status_changed(media::Player::PlaybackStatus::playing);
269  }
270 
271  return result;
272 }
273 
275 {
276  // No need to wait, and we can immediately return.
277  if (d->state == media::Engine::State::stopped)
278  return true;
279 
280  auto result = d->playbin.set_state_and_wait(GST_STATE_NULL);
281 
282  if (result)
283  {
284  d->state = media::Engine::State::stopped;
285  cout << "stop" << endl;
286  d->playback_status_changed(media::Player::PlaybackStatus::stopped);
287  }
288 
289  return result;
290 }
291 
293 {
294  auto result = d->playbin.set_state_and_wait(GST_STATE_PAUSED);
295 
296  if (result)
297  {
298  d->state = media::Engine::State::paused;
299  cout << "pause" << endl;
300  d->playback_status_changed(media::Player::PlaybackStatus::paused);
301  }
302 
303  return result;
304 }
305 
306 bool gstreamer::Engine::seek_to(const std::chrono::microseconds& ts)
307 {
308  return d->playbin.seek(ts);
309 }
310 
311 const core::Property<bool>& gstreamer::Engine::is_video_source() const
312 {
313  gstreamer::Playbin::MediaFileType type = d->playbin.media_file_type();
314  if (type == gstreamer::Playbin::MediaFileType::MEDIA_FILE_TYPE_VIDEO)
315  d->is_video_source.set(true);
316  else
317  d->is_video_source.set(false);
318 
319  return d->is_video_source;
320 }
321 
322 const core::Property<bool>& gstreamer::Engine::is_audio_source() const
323 {
324  gstreamer::Playbin::MediaFileType type = d->playbin.media_file_type();
325  if (type == gstreamer::Playbin::MediaFileType::MEDIA_FILE_TYPE_AUDIO)
326  d->is_audio_source.set(true);
327  else
328  d->is_audio_source.set(false);
329 
330  return d->is_audio_source;
331 }
332 
333 const core::Property<uint64_t>& gstreamer::Engine::position() const
334 {
335  d->position.set(d->playbin.position());
336  return d->position;
337 }
338 
339 const core::Property<uint64_t>& gstreamer::Engine::duration() const
340 {
341  d->duration.set(d->playbin.duration());
342  return d->duration;
343 }
344 
345 const core::Property<core::ubuntu::media::Engine::Volume>& gstreamer::Engine::volume() const
346 {
347  return d->volume;
348 }
349 
350 core::Property<core::ubuntu::media::Engine::Volume>& gstreamer::Engine::volume()
351 {
352  return d->volume;
353 }
354 
355 const core::Property<core::ubuntu::media::Player::AudioStreamRole>& gstreamer::Engine::audio_stream_role() const
356 {
357  return d->audio_role;
358 }
359 
360 const core::Property<core::ubuntu::media::Player::Lifetime>& gstreamer::Engine::lifetime() const
361 {
362  return d->lifetime;
363 }
364 
365 core::Property<core::ubuntu::media::Player::AudioStreamRole>& gstreamer::Engine::audio_stream_role()
366 {
367  return d->audio_role;
368 }
369 
370 const core::Property<core::ubuntu::media::Player::Orientation>& gstreamer::Engine::orientation() const
371 {
372  return d->orientation;
373 }
374 
375 core::Property<core::ubuntu::media::Player::Lifetime>& gstreamer::Engine::lifetime()
376 {
377  return d->lifetime;
378 }
379 
380 const core::Property<std::tuple<media::Track::UriType, media::Track::MetaData>>&
382 {
383  return d->track_meta_data;
384 }
385 
386 const core::Signal<void>& gstreamer::Engine::about_to_finish_signal() const
387 {
388  return d->about_to_finish;
389 }
390 
391 const core::Signal<uint64_t>& gstreamer::Engine::seeked_to_signal() const
392 {
393  return d->seeked_to;
394 }
395 
396 const core::Signal<void>& gstreamer::Engine::client_disconnected_signal() const
397 {
398  return d->client_disconnected;
399 }
400 
401 const core::Signal<void>& gstreamer::Engine::end_of_stream_signal() const
402 {
403  return d->end_of_stream;
404 }
405 
406 const core::Signal<media::Player::PlaybackStatus>& gstreamer::Engine::playback_status_changed_signal() const
407 {
408  return d->playback_status_changed;
409 }
410 
411 const core::Signal<uint32_t, uint32_t>& gstreamer::Engine::video_dimension_changed_signal() const
412 {
413  return d->video_dimension_changed;
414 }
415 
417 {
418  d->playbin.reset();
419 }
void on_tag_available(const gstreamer::Bus::Message::Detail::Tag &tag)
Definition: engine.cpp:58
core::ScopedConnection on_state_changed_connection
Definition: engine.cpp:203
bool open_resource_for_uri(const core::ubuntu::media::Track::UriType &uri)
core::ScopedConnection on_video_dimension_changed_connection
Definition: engine.cpp:212
const core::Property< core::ubuntu::media::Engine::Volume > & volume() const
Definition: engine.cpp:345
core::Property< bool > is_video_source
Definition: engine.cpp:199
const core::Signal< core::ubuntu::media::Player::PlaybackStatus > & playback_status_changed_signal() const
Definition: engine.cpp:406
const core::Property< core::ubuntu::media::Player::AudioStreamRole > & audio_stream_role() const
Definition: engine.cpp:355
const core::Property< bool > & is_video_source() const
Definition: engine.cpp:311
void on_video_dimension_changed(uint32_t height, uint32_t width)
Definition: engine.cpp:108
const core::Signal< void > & client_disconnected_signal() const
Definition: engine.cpp:396
core::Signal< void > end_of_stream
Definition: engine.cpp:217
Definition: bus.h:33
core::ScopedConnection on_lifetime_changed_connection
Definition: engine.cpp:208
void on_seeked_to(uint64_t value)
Definition: engine.cpp:93
STL namespace.
const core::Property< State > & state() const
Definition: engine.cpp:238
const core::Property< core::ubuntu::media::Player::Lifetime > & lifetime() const
Definition: engine.cpp:360
core::ScopedConnection on_seeked_to_connection
Definition: engine.cpp:209
core::ScopedConnection on_end_of_stream_connection
Definition: engine.cpp:211
void on_orientation_changed(const media::Player::Orientation &o)
Definition: engine.cpp:75
std::map< std::string, std::string > HeadersType
Definition: player.h:45
gstreamer::Playbin playbin
Definition: engine.cpp:188
bool seek_to(const std::chrono::microseconds &ts)
Definition: engine.cpp:306
const core::Signal< uint64_t > & seeked_to_signal() const
Definition: engine.cpp:391
struct gstreamer::Init init
void create_video_sink(uint32_t texture_id)
Definition: engine.cpp:255
const core::Property< std::tuple< core::ubuntu::media::Track::UriType, core::ubuntu::media::Track::MetaData > > & track_meta_data() const
Definition: engine.cpp:381
core::ScopedConnection client_disconnected_connection
Definition: engine.cpp:210
const core::Signal< uint32_t, uint32_t > & video_dimension_changed_signal() const
Definition: engine.cpp:411
const core::Property< bool > & is_audio_source() const
Definition: engine.cpp:322
void on_volume_changed(const media::Engine::Volume &new_volume)
Definition: engine.cpp:65
const core::Property< uint64_t > & duration() const
Definition: engine.cpp:339
core::ScopedConnection on_volume_changed_connection
Definition: engine.cpp:205
const core::Signal< void > & about_to_finish_signal() const
Definition: engine.cpp:386
core::Property< media::Player::Orientation > orientation
Definition: engine.cpp:197
core::Property< media::Player::AudioStreamRole > audio_role
Definition: engine.cpp:196
core::Signal< uint32_t, uint32_t > video_dimension_changed
Definition: engine.cpp:219
const core::Signal< void > & end_of_stream_signal() const
Definition: engine.cpp:401
core::Signal< void > client_disconnected
Definition: engine.cpp:216
core::Signal< uint64_t > seeked_to
Definition: engine.cpp:215
core::Property< media::Player::Lifetime > lifetime
Definition: engine.cpp:198
std::shared_ptr< Engine::MetaDataExtractor > meta_data_extractor
Definition: engine.cpp:190
void on_playbin_state_changed(const gstreamer::Bus::Message::Detail::StateChanged &state_change)
Definition: engine.cpp:52
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:204
const std::shared_ptr< MetaDataExtractor > & meta_data_extractor() const
Definition: engine.cpp:233
core::Property< media::Engine::Volume > volume
Definition: engine.cpp:195
std::string UriType
Definition: track.h:40
core::ScopedConnection about_to_finish_connection
Definition: engine.cpp:202
core::Property< Engine::State > state
Definition: engine.cpp:191
const core::Property< core::ubuntu::media::Player::Orientation > & orientation() const
Definition: engine.cpp:370
core::Property< uint64_t > position
Definition: engine.cpp:193
core::Property< std::tuple< media::Track::UriType, media::Track::MetaData > > track_meta_data
Definition: engine.cpp:192
core::Signal< void > about_to_finish
Definition: engine.cpp:214
core::Signal< media::Player::PlaybackStatus > playback_status_changed
Definition: engine.cpp:218
const core::Property< uint64_t > & position() const
Definition: engine.cpp:333
core::ScopedConnection on_orientation_changed_connection
Definition: engine.cpp:207
void on_audio_stream_role_changed(const media::Player::AudioStreamRole &new_audio_role)
Definition: engine.cpp:70
void on_lifetime_changed(const media::Player::Lifetime &lifetime)
Definition: engine.cpp:82
core::Property< bool > is_audio_source
Definition: engine.cpp:200
core::Property< uint64_t > duration
Definition: engine.cpp:194
core::ScopedConnection on_audio_stream_role_changed_connection
Definition: engine.cpp:206