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 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  end_of_stream();
181  }
182 
184  : meta_data_extractor(new gstreamer::MetaDataExtractor()),
185  volume(media::Engine::Volume(1.)),
186  is_video_source(false),
187  is_audio_source(false),
188  about_to_finish_connection(
189  playbin.signals.about_to_finish.connect(
190  std::bind(
191  &Private::on_about_to_finish,
192  this))),
193  on_state_changed_connection(
194  playbin.signals.on_state_changed.connect(
195  std::bind(
196  &Private::on_playbin_state_changed,
197  this,
198  std::placeholders::_1))),
199  on_tag_available_connection(
200  playbin.signals.on_tag_available.connect(
201  std::bind(
202  &Private::on_tag_available,
203  this,
204  std::placeholders::_1))),
205  on_volume_changed_connection(
206  volume.changed().connect(
207  std::bind(
208  &Private::on_volume_changed,
209  this,
210  std::placeholders::_1))),
211  on_seeked_to_connection(
212  playbin.signals.on_seeked_to.connect(
213  std::bind(
214  &Private::on_seeked_to,
215  this,
216  std::placeholders::_1))),
217  on_end_of_stream_connection(
218  playbin.signals.on_end_of_stream.connect(
219  std::bind(
220  &Private::on_end_of_stream,
221  this)))
222  {
223  }
224 
225  std::shared_ptr<Engine::MetaDataExtractor> meta_data_extractor;
226  core::Property<Engine::State> state;
227  core::Property<std::tuple<media::Track::UriType, media::Track::MetaData>> track_meta_data;
228  core::Property<uint64_t> position;
229  core::Property<uint64_t> duration;
230  core::Property<media::Engine::Volume> volume;
231  core::Property<bool> is_video_source;
232  core::Property<bool> is_audio_source;
234  core::ScopedConnection about_to_finish_connection;
235  core::ScopedConnection on_state_changed_connection;
236  core::ScopedConnection on_tag_available_connection;
237  core::ScopedConnection on_volume_changed_connection;
238  core::ScopedConnection on_seeked_to_connection;
239  core::ScopedConnection on_end_of_stream_connection;
240 
241  core::Signal<void> about_to_finish;
242  core::Signal<uint64_t> seeked_to;
243  core::Signal<void> end_of_stream;
244  core::Signal<media::Player::PlaybackStatus> playback_status_changed;
245 };
246 
248 {
249  cout << "Creating a new Engine instance in " << __PRETTY_FUNCTION__ << endl;
250  d->state = media::Engine::State::ready;
251 }
252 
254 {
255  stop();
256 }
257 
258 const std::shared_ptr<media::Engine::MetaDataExtractor>& gstreamer::Engine::meta_data_extractor() const
259 {
260  return d->meta_data_extractor;
261 }
262 
263 const core::Property<media::Engine::State>& gstreamer::Engine::state() const
264 {
265  return d->state;
266 }
267 
269 {
270  d->playbin.set_uri(uri);
271  return true;
272 }
273 
274 void gstreamer::Engine::create_video_sink(uint32_t texture_id)
275 {
276  d->playbin.create_video_sink(texture_id);
277 }
278 
280 {
281  auto result = d->playbin.set_state_and_wait(GST_STATE_PLAYING);
282 
283  if (result)
284  {
285  d->state = media::Engine::State::playing;
286  d->playback_status_changed(media::Player::PlaybackStatus::playing);
287  }
288 
289  cout << "Engine: " << this << endl;
290 
291  return result;
292 }
293 
295 {
296  auto result = d->playbin.set_state_and_wait(GST_STATE_NULL);
297 
298  if (result)
299  {
300  d->state = media::Engine::State::stopped;
301  d->playback_status_changed(media::Player::PlaybackStatus::stopped);
302  }
303 
304  return result;
305 }
306 
308 {
309  auto result = d->playbin.set_state_and_wait(GST_STATE_PAUSED);
310 
311  if (result)
312  {
313  d->state = media::Engine::State::paused;
314  cout << "pause" << endl;
315  d->playback_status_changed(media::Player::PlaybackStatus::paused);
316  }
317 
318  return result;
319 }
320 
321 bool gstreamer::Engine::seek_to(const std::chrono::microseconds& ts)
322 {
323  return d->playbin.seek(ts);
324 }
325 
326 const core::Property<bool>& gstreamer::Engine::is_video_source() const
327 {
328  gstreamer::Playbin::MediaFileType type = d->playbin.media_file_type();
329  if (type == gstreamer::Playbin::MediaFileType::MEDIA_FILE_TYPE_VIDEO)
330  d->is_video_source.set(true);
331  else
332  d->is_video_source.set(false);
333 
334  return d->is_video_source;
335 }
336 
337 const core::Property<bool>& gstreamer::Engine::is_audio_source() const
338 {
339  gstreamer::Playbin::MediaFileType type = d->playbin.media_file_type();
340  if (type == gstreamer::Playbin::MediaFileType::MEDIA_FILE_TYPE_AUDIO)
341  d->is_audio_source.set(true);
342  else
343  d->is_audio_source.set(false);
344 
345  return d->is_audio_source;
346 }
347 
348 const core::Property<uint64_t>& gstreamer::Engine::position() const
349 {
350  d->position.set(d->playbin.position());
351  return d->position;
352 }
353 
354 const core::Property<uint64_t>& gstreamer::Engine::duration() const
355 {
356  d->duration.set(d->playbin.duration());
357  return d->duration;
358 }
359 
360 const core::Property<core::ubuntu::media::Engine::Volume>& gstreamer::Engine::volume() const
361 {
362  return d->volume;
363 }
364 
365 core::Property<core::ubuntu::media::Engine::Volume>& gstreamer::Engine::volume()
366 {
367  return d->volume;
368 }
369 
370 const core::Property<std::tuple<media::Track::UriType, media::Track::MetaData>>&
372 {
373  return d->track_meta_data;
374 }
375 
376 const core::Signal<void>& gstreamer::Engine::about_to_finish_signal() const
377 {
378  return d->about_to_finish;
379 }
380 
381 const core::Signal<uint64_t>& gstreamer::Engine::seeked_to_signal() const
382 {
383  return d->seeked_to;
384 }
385 
386 const core::Signal<void>& gstreamer::Engine::end_of_stream_signal() const
387 {
388  return d->end_of_stream;
389 }
390 
391 const core::Signal<media::Player::PlaybackStatus>& gstreamer::Engine::playback_status_changed_signal() const
392 {
393  return d->playback_status_changed;
394 }
void on_tag_available(const gstreamer::Bus::Message::Detail::Tag &tag)
Definition: engine.cpp:57
core::ScopedConnection on_state_changed_connection
Definition: engine.cpp:235
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:360
core::Property< bool > is_video_source
Definition: engine.cpp:231
const core::Signal< core::ubuntu::media::Player::PlaybackStatus > & playback_status_changed_signal() const
Definition: engine.cpp:391
const core::Property< bool > & is_video_source() const
Definition: engine.cpp:326
core::Signal< void > end_of_stream
Definition: engine.cpp:243
void on_seeked_to(uint64_t value)
Definition: engine.cpp:173
const core::Property< State > & state() const
Definition: engine.cpp:263
core::ScopedConnection on_seeked_to_connection
Definition: engine.cpp:238
core::ScopedConnection on_end_of_stream_connection
Definition: engine.cpp:239
gstreamer::Playbin playbin
Definition: engine.cpp:233
bool seek_to(const std::chrono::microseconds &ts)
Definition: engine.cpp:321
const core::Signal< uint64_t > & seeked_to_signal() const
Definition: engine.cpp:381
struct gstreamer::Init init
void create_video_sink(uint32_t texture_id)
Definition: engine.cpp:274
const core::Property< std::tuple< core::ubuntu::media::Track::UriType, core::ubuntu::media::Track::MetaData > > & track_meta_data() const
Definition: engine.cpp:371
const core::Property< bool > & is_audio_source() const
Definition: engine.cpp:337
void on_volume_changed(const media::Engine::Volume &new_volume)
Definition: engine.cpp:162
const core::Property< uint64_t > & duration() const
Definition: engine.cpp:354
core::ScopedConnection on_volume_changed_connection
Definition: engine.cpp:237
const core::Signal< void > & about_to_finish_signal() const
Definition: engine.cpp:376
const core::Signal< void > & end_of_stream_signal() const
Definition: engine.cpp:386
core::Signal< uint64_t > seeked_to
Definition: engine.cpp:242
std::shared_ptr< Engine::MetaDataExtractor > meta_data_extractor
Definition: engine.cpp:225
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:236
const std::shared_ptr< MetaDataExtractor > & meta_data_extractor() const
Definition: engine.cpp:258
core::Property< media::Engine::Volume > volume
Definition: engine.cpp:230
std::string UriType
Definition: track.h:40
core::ScopedConnection about_to_finish_connection
Definition: engine.cpp:234
core::Property< Engine::State > state
Definition: engine.cpp:226
core::Property< uint64_t > position
Definition: engine.cpp:228
core::Property< std::tuple< media::Track::UriType, media::Track::MetaData > > track_meta_data
Definition: engine.cpp:227
core::Signal< void > about_to_finish
Definition: engine.cpp:241
core::Signal< media::Player::PlaybackStatus > playback_status_changed
Definition: engine.cpp:244
const core::Property< uint64_t > & position() const
Definition: engine.cpp:348
core::Property< bool > is_audio_source
Definition: engine.cpp:232
core::Property< uint64_t > duration
Definition: engine.cpp:229