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