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  */
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 
22 #include "bus.h"
23 #include "engine.h"
24 #include "meta_data_extractor.h"
25 #include "playbin.h"
26 
27 #include <cassert>
28 
29 namespace media = core::ubuntu::media;
30 
31 using namespace std;
32 
33 namespace gstreamer
34 {
35 struct Init
36 {
37  Init()
38  {
39  gst_init(nullptr, nullptr);
40  }
41 
43  {
44  gst_deinit();
45  }
46 } init;
47 }
48 
50 {
53  {
54  (void) state_change;
55  }
56 
58  {
59  media::Track::MetaData md;
60 
61  gst_tag_list_foreach(
62  tag.tag_list,
63  [](const GstTagList *list,
64  const gchar* tag,
65  gpointer user_data)
66  {
67  (void) list;
68 
69  static const std::map<std::string, std::string> gstreamer_to_mpris_tag_lut =
70  {
71  {GST_TAG_ALBUM, media::Engine::Xesam::album()},
72  {GST_TAG_ALBUM_ARTIST, media::Engine::Xesam::album_artist()},
73  {GST_TAG_ARTIST, media::Engine::Xesam::artist()},
74  {GST_TAG_LYRICS, media::Engine::Xesam::as_text()},
75  {GST_TAG_COMMENT, media::Engine::Xesam::comment()},
76  {GST_TAG_COMPOSER, media::Engine::Xesam::composer()},
77  {GST_TAG_DATE, media::Engine::Xesam::content_created()},
78  {GST_TAG_ALBUM_VOLUME_NUMBER, media::Engine::Xesam::disc_number()},
79  {GST_TAG_GENRE, media::Engine::Xesam::genre()},
80  {GST_TAG_TITLE, media::Engine::Xesam::title()},
81  {GST_TAG_TRACK_NUMBER, media::Engine::Xesam::track_number()},
82  {GST_TAG_USER_RATING, media::Engine::Xesam::user_rating()}
83  };
84 
85  auto md = static_cast<media::Track::MetaData*>(user_data);
86  std::stringstream ss;
87 
88  switch(gst_tag_get_type(tag))
89  {
90  case G_TYPE_BOOLEAN:
91  {
92  gboolean value;
93  if (gst_tag_list_get_boolean(list, tag, &value))
94  ss << value;
95  break;
96  }
97  case G_TYPE_INT:
98  {
99  gint value;
100  if (gst_tag_list_get_int(list, tag, &value))
101  ss << value;
102  break;
103  }
104  case G_TYPE_UINT:
105  {
106  guint value;
107  if (gst_tag_list_get_uint(list, tag, &value))
108  ss << value;
109  break;
110  }
111  case G_TYPE_INT64:
112  {
113  gint64 value;
114  if (gst_tag_list_get_int64(list, tag, &value))
115  ss << value;
116  break;
117  }
118  case G_TYPE_UINT64:
119  {
120  guint64 value;
121  if (gst_tag_list_get_uint64(list, tag, &value))
122  ss << value;
123  break;
124  }
125  case G_TYPE_FLOAT:
126  {
127  gfloat value;
128  if (gst_tag_list_get_float(list, tag, &value))
129  ss << value;
130  break;
131  }
132  case G_TYPE_DOUBLE:
133  {
134  double value;
135  if (gst_tag_list_get_double(list, tag, &value))
136  ss << value;
137  break;
138  }
139  case G_TYPE_STRING:
140  {
141  gchar* value;
142  if (gst_tag_list_get_string(list, tag, &value))
143  {
144  ss << value;
145  g_free(value);
146  }
147  break;
148  }
149  default:
150  break;
151  }
152 
153  (*md).set(
154  (gstreamer_to_mpris_tag_lut.count(tag) > 0 ? gstreamer_to_mpris_tag_lut.at(tag) : tag),
155  ss.str());
156  },
157  &md);
158 
159  track_meta_data.set(std::make_tuple(playbin.uri(), md));
160  }
161 
162  void on_volume_changed(const media::Engine::Volume& new_volume)
163  {
164  playbin.set_volume(new_volume.value);
165  }
166 
168  {
169  state = Engine::State::ready;
170  about_to_finish();
171  }
172 
173  void on_seeked_to(uint64_t value)
174  {
175  seeked_to(value);
176  }
177 
179  {
180  client_disconnected();
181  }
182 
184  {
185  end_of_stream();
186  }
187 
189  : meta_data_extractor(new gstreamer::MetaDataExtractor()),
190  volume(media::Engine::Volume(1.)),
191  is_video_source(false),
192  is_audio_source(false),
193  about_to_finish_connection(
194  playbin.signals.about_to_finish.connect(
195  std::bind(
196  &Private::on_about_to_finish,
197  this))),
198  on_state_changed_connection(
199  playbin.signals.on_state_changed.connect(
200  std::bind(
201  &Private::on_playbin_state_changed,
202  this,
203  std::placeholders::_1))),
204  on_tag_available_connection(
205  playbin.signals.on_tag_available.connect(
206  std::bind(
207  &Private::on_tag_available,
208  this,
209  std::placeholders::_1))),
210  on_volume_changed_connection(
211  volume.changed().connect(
212  std::bind(
213  &Private::on_volume_changed,
214  this,
215  std::placeholders::_1))),
216  on_seeked_to_connection(
217  playbin.signals.on_seeked_to.connect(
218  std::bind(
219  &Private::on_seeked_to,
220  this,
221  std::placeholders::_1))),
222  client_disconnected_connection(
223  playbin.signals.client_disconnected.connect(
224  std::bind(
225  &Private::on_client_disconnected,
226  this))),
227  on_end_of_stream_connection(
228  playbin.signals.on_end_of_stream.connect(
229  std::bind(
230  &Private::on_end_of_stream,
231  this)))
232  {
233  }
234 
235  std::shared_ptr<Engine::MetaDataExtractor> meta_data_extractor;
236  core::Property<Engine::State> state;
237  core::Property<std::tuple<media::Track::UriType, media::Track::MetaData>> track_meta_data;
238  core::Property<uint64_t> position;
239  core::Property<uint64_t> duration;
240  core::Property<media::Engine::Volume> volume;
241  core::Property<bool> is_video_source;
242  core::Property<bool> is_audio_source;
244  core::ScopedConnection about_to_finish_connection;
245  core::ScopedConnection on_state_changed_connection;
246  core::ScopedConnection on_tag_available_connection;
247  core::ScopedConnection on_volume_changed_connection;
248  core::ScopedConnection on_seeked_to_connection;
249  core::ScopedConnection client_disconnected_connection;
250  core::ScopedConnection on_end_of_stream_connection;
251 
252  core::Signal<void> about_to_finish;
253  core::Signal<uint64_t> seeked_to;
254  core::Signal<void> client_disconnected;
255  core::Signal<void> end_of_stream;
256  core::Signal<media::Player::PlaybackStatus> playback_status_changed;
257 };
258 
260 {
261  cout << "Creating a new Engine instance in " << __PRETTY_FUNCTION__ << endl;
262  d->state = media::Engine::State::ready;
263 }
264 
266 {
267  stop();
268 }
269 
270 const std::shared_ptr<media::Engine::MetaDataExtractor>& gstreamer::Engine::meta_data_extractor() const
271 {
272  return d->meta_data_extractor;
273 }
274 
275 const core::Property<media::Engine::State>& gstreamer::Engine::state() const
276 {
277  return d->state;
278 }
279 
281 {
282  d->playbin.set_uri(uri);
283  return true;
284 }
285 
286 void gstreamer::Engine::create_video_sink(uint32_t texture_id)
287 {
288  d->playbin.create_video_sink(texture_id);
289 }
290 
292 {
293  auto result = d->playbin.set_state_and_wait(GST_STATE_PLAYING);
294 
295  if (result)
296  {
297  d->state = media::Engine::State::playing;
298  d->playback_status_changed(media::Player::PlaybackStatus::playing);
299  }
300 
301  cout << "Engine: " << this << endl;
302 
303  return result;
304 }
305 
307 {
308  auto result = d->playbin.set_state_and_wait(GST_STATE_NULL);
309 
310  if (result)
311  {
312  d->state = media::Engine::State::stopped;
313  d->playback_status_changed(media::Player::PlaybackStatus::stopped);
314  }
315 
316  return result;
317 }
318 
320 {
321  auto result = d->playbin.set_state_and_wait(GST_STATE_PAUSED);
322 
323  if (result)
324  {
325  d->state = media::Engine::State::paused;
326  cout << "pause" << endl;
327  d->playback_status_changed(media::Player::PlaybackStatus::paused);
328  }
329 
330  return result;
331 }
332 
333 bool gstreamer::Engine::seek_to(const std::chrono::microseconds& ts)
334 {
335  return d->playbin.seek(ts);
336 }
337 
338 const core::Property<bool>& gstreamer::Engine::is_video_source() const
339 {
340  gstreamer::Playbin::MediaFileType type = d->playbin.media_file_type();
341  if (type == gstreamer::Playbin::MediaFileType::MEDIA_FILE_TYPE_VIDEO)
342  d->is_video_source.set(true);
343  else
344  d->is_video_source.set(false);
345 
346  return d->is_video_source;
347 }
348 
349 const core::Property<bool>& gstreamer::Engine::is_audio_source() const
350 {
351  gstreamer::Playbin::MediaFileType type = d->playbin.media_file_type();
352  if (type == gstreamer::Playbin::MediaFileType::MEDIA_FILE_TYPE_AUDIO)
353  d->is_audio_source.set(true);
354  else
355  d->is_audio_source.set(false);
356 
357  return d->is_audio_source;
358 }
359 
360 const core::Property<uint64_t>& gstreamer::Engine::position() const
361 {
362  d->position.set(d->playbin.position());
363  return d->position;
364 }
365 
366 const core::Property<uint64_t>& gstreamer::Engine::duration() const
367 {
368  d->duration.set(d->playbin.duration());
369  return d->duration;
370 }
371 
372 const core::Property<core::ubuntu::media::Engine::Volume>& gstreamer::Engine::volume() const
373 {
374  return d->volume;
375 }
376 
377 core::Property<core::ubuntu::media::Engine::Volume>& gstreamer::Engine::volume()
378 {
379  return d->volume;
380 }
381 
382 const core::Property<std::tuple<media::Track::UriType, media::Track::MetaData>>&
384 {
385  return d->track_meta_data;
386 }
387 
388 const core::Signal<void>& gstreamer::Engine::about_to_finish_signal() const
389 {
390  return d->about_to_finish;
391 }
392 
393 const core::Signal<uint64_t>& gstreamer::Engine::seeked_to_signal() const
394 {
395  return d->seeked_to;
396 }
397 
398 const core::Signal<void>& gstreamer::Engine::client_disconnected_signal() const
399 {
400  return d->client_disconnected;
401 }
402 
403 const core::Signal<void>& gstreamer::Engine::end_of_stream_signal() const
404 {
405  return d->end_of_stream;
406 }
407 
408 const core::Signal<media::Player::PlaybackStatus>& gstreamer::Engine::playback_status_changed_signal() const
409 {
410  return d->playback_status_changed;
411 }
void on_tag_available(const gstreamer::Bus::Message::Detail::Tag &tag)
Definition: engine.cpp:57
core::ScopedConnection on_state_changed_connection
Definition: engine.cpp:245
bool open_resource_for_uri(const core::ubuntu::media::Track::UriType &uri)
const core::Property< core::ubuntu::media::Engine::Volume > & volume() const
Definition: engine.cpp:372
core::Property< bool > is_video_source
Definition: engine.cpp:241
const core::Signal< core::ubuntu::media::Player::PlaybackStatus > & playback_status_changed_signal() const
Definition: engine.cpp:408
const core::Property< bool > & is_video_source() const
Definition: engine.cpp:338
const core::Signal< void > & client_disconnected_signal() const
Definition: engine.cpp:398
core::Signal< void > end_of_stream
Definition: engine.cpp:255
void on_seeked_to(uint64_t value)
Definition: engine.cpp:173
const core::Property< State > & state() const
Definition: engine.cpp:275
core::ScopedConnection on_seeked_to_connection
Definition: engine.cpp:248
core::ScopedConnection on_end_of_stream_connection
Definition: engine.cpp:250
gstreamer::Playbin playbin
Definition: engine.cpp:243
bool seek_to(const std::chrono::microseconds &ts)
Definition: engine.cpp:333
const core::Signal< uint64_t > & seeked_to_signal() const
Definition: engine.cpp:393
struct gstreamer::Init init
void create_video_sink(uint32_t texture_id)
Definition: engine.cpp:286
const core::Property< std::tuple< core::ubuntu::media::Track::UriType, core::ubuntu::media::Track::MetaData > > & track_meta_data() const
Definition: engine.cpp:383
core::ScopedConnection client_disconnected_connection
Definition: engine.cpp:249
const core::Property< bool > & is_audio_source() const
Definition: engine.cpp:349
void on_volume_changed(const media::Engine::Volume &new_volume)
Definition: engine.cpp:162
const core::Property< uint64_t > & duration() const
Definition: engine.cpp:366
core::ScopedConnection on_volume_changed_connection
Definition: engine.cpp:247
const core::Signal< void > & about_to_finish_signal() const
Definition: engine.cpp:388
const core::Signal< void > & end_of_stream_signal() const
Definition: engine.cpp:403
core::Signal< void > client_disconnected
Definition: engine.cpp:254
core::Signal< uint64_t > seeked_to
Definition: engine.cpp:253
std::shared_ptr< Engine::MetaDataExtractor > meta_data_extractor
Definition: engine.cpp:235
void on_playbin_state_changed(const gstreamer::Bus::Message::Detail::StateChanged &state_change)
Definition: engine.cpp:51
core::ScopedConnection on_tag_available_connection
Definition: engine.cpp:246
const std::shared_ptr< MetaDataExtractor > & meta_data_extractor() const
Definition: engine.cpp:270
core::Property< media::Engine::Volume > volume
Definition: engine.cpp:240
std::string UriType
Definition: track.h:40
core::ScopedConnection about_to_finish_connection
Definition: engine.cpp:244
core::Property< Engine::State > state
Definition: engine.cpp:236
core::Property< uint64_t > position
Definition: engine.cpp:238
core::Property< std::tuple< media::Track::UriType, media::Track::MetaData > > track_meta_data
Definition: engine.cpp:237
core::Signal< void > about_to_finish
Definition: engine.cpp:252
core::Signal< media::Player::PlaybackStatus > playback_status_changed
Definition: engine.cpp:256
const core::Property< uint64_t > & position() const
Definition: engine.cpp:360
core::Property< bool > is_audio_source
Definition: engine.cpp:242
core::Property< uint64_t > duration
Definition: engine.cpp:239