Music Hub  ..
A session-wide music playback service
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
player_implementation.cpp
Go to the documentation of this file.
1 /*
2  *
3  * This program is free software: you can redistribute it and/or modify it
4  * under the terms of the GNU Lesser General Public License version 3,
5  * as published by the Free Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU Lesser General Public License for more details.
11  *
12  * You should have received a copy of the GNU Lesser General Public License
13  * along with this program. If not, see <http://www.gnu.org/licenses/>.
14  *
15  * Authored by: Thomas Voß <thomas.voss@canonical.com>
16  */
17 
18 #include "player_implementation.h"
19 
20 #include <unistd.h>
21 
22 #include "engine.h"
24 
25 #include "powerd_service.h"
26 #include "unity_screen_service.h"
27 #include "gstreamer/engine.h"
28 
29 #include <exception>
30 #include <iostream>
31 
32 #define UNUSED __attribute__((unused))
33 
34 namespace media = core::ubuntu::media;
35 namespace dbus = core::dbus;
36 
37 using namespace std;
38 
40 {
41  Private(PlayerImplementation* parent,
42  const dbus::types::ObjectPath& session_path,
43  const std::shared_ptr<media::Service>& service,
44  PlayerImplementation::PlayerKey key)
45  : parent(parent),
46  service(service),
47  engine(std::make_shared<gstreamer::Engine>()),
48  session_path(session_path),
49  track_list(
50  new media::TrackListImplementation(
51  session_path.as_string() + "/TrackList",
52  engine->meta_data_extractor())),
53  sys_lock_name("media-hub-music-playback"),
54  active_display_on_request(false),
55  key(key)
56  {
57  auto bus = std::shared_ptr<dbus::Bus>(new dbus::Bus(core::dbus::WellKnownBus::system));
58  bus->install_executor(dbus::asio::make_executor(bus));
59 
60  auto stub_service = dbus::Service::use_service(bus, dbus::traits::Service<core::Powerd>::interface_name());
61  powerd_session = stub_service->object_for_path(dbus::types::ObjectPath("/com/canonical/powerd"));
62 
63  auto uscreen_stub_service = dbus::Service::use_service(bus, dbus::traits::Service<core::UScreen>::interface_name());
64  uscreen_session = uscreen_stub_service->object_for_path(dbus::types::ObjectPath("/com/canonical/Unity/Screen"));
65 
66  engine->state().changed().connect(
67  [parent, this](const Engine::State& state)
68  {
69  switch(state)
70  {
71  case Engine::State::ready:
72  {
73  parent->playback_status().set(media::Player::ready);
74  clear_power_state();
75  break;
76  }
77  case Engine::State::playing:
78  {
79  parent->playback_status().set(media::Player::playing);
80  request_power_state();
81  break;
82  }
83  case Engine::State::stopped:
84  {
85  parent->playback_status().set(media::Player::stopped);
86  clear_power_state();
87  break;
88  }
89  case Engine::State::paused:
90  {
91  parent->playback_status().set(media::Player::paused);
92  clear_power_state();
93  break;
94  }
95  default:
96  break;
97  };
98  });
99 
100  }
101 
103  {
104  try
105  {
106  if (parent->is_video_source())
107  {
108  if (!active_display_on_request)
109  {
110  auto result = uscreen_session->invoke_method_synchronously<core::UScreen::keepDisplayOn, int>();
111  if (result.is_error())
112  throw std::runtime_error(result.error().print());
113 
114  disp_cookie = result.value();
115  active_display_on_request = true;
116  }
117  }
118  else
119  {
120  if (sys_cookie.empty())
121  {
122  auto result = powerd_session->invoke_method_synchronously<core::Powerd::requestSysState, std::string>(sys_lock_name, static_cast<int>(1));
123  if (result.is_error())
124  throw std::runtime_error(result.error().print());
125 
126  sys_cookie = result.value();
127  }
128  }
129  }
130  catch(std::exception& e)
131  {
132  std::cerr << "Warning: failed to request power state: ";
133  std::cerr << e.what() << std::endl;
134  }
135  }
136 
138  {
139  try
140  {
141  if (parent->is_video_source())
142  {
143  if (active_display_on_request)
144  {
145  uscreen_session->invoke_method_synchronously<core::UScreen::removeDisplayOnRequest, void>(disp_cookie);
146  active_display_on_request = false;
147  }
148  }
149  else
150  {
151  if (!sys_cookie.empty())
152  {
153  powerd_session->invoke_method_synchronously<core::Powerd::clearSysState, void>(sys_cookie);
154  sys_cookie.clear();
155  }
156  }
157  }
158  catch(std::exception& e)
159  {
160  std::cerr << "Warning: failed to clear power state: ";
161  std::cerr << e.what() << std::endl;
162  }
163  }
164 
165  PlayerImplementation* parent;
166  std::shared_ptr<Service> service;
167  std::shared_ptr<Engine> engine;
168  dbus::types::ObjectPath session_path;
169  std::shared_ptr<TrackListImplementation> track_list;
170  std::shared_ptr<dbus::Object> powerd_session;
171  std::shared_ptr<dbus::Object> uscreen_session;
172  std::string sys_lock_name;
175  std::string sys_cookie;
176  PlayerImplementation::PlayerKey key;
177 };
178 
180  const dbus::types::ObjectPath& session_path,
181  const std::shared_ptr<Service>& service,
182  PlayerKey key)
183  : media::PlayerSkeleton(session_path),
184  d(new Private(
185  this,
186  session_path,
187  service,
188  key))
189 {
190  // Initializing default values for properties
191  can_play().set(true);
192  can_pause().set(true);
193  can_seek().set(true);
194  can_go_previous().set(true);
195  can_go_next().set(true);
196  is_video_source().set(false);
197  is_audio_source().set(false);
198  is_shuffle().set(true);
199  playback_rate().set(1.f);
200  playback_status().set(Player::PlaybackStatus::null);
201  loop_status().set(Player::LoopStatus::none);
202  position().set(0);
203  duration().set(0);
204 
205  // Make sure that the Position property gets updated from the Engine
206  // every time the client requests position
207  std::function<uint64_t()> position_getter = [this]()
208  {
209  return d->engine->position().get();
210  };
211  position().install(position_getter);
212 
213  // Make sure that the Duration property gets updated from the Engine
214  // every time the client requests duration
215  std::function<uint64_t()> duration_getter = [this]()
216  {
217  return d->engine->duration().get();
218  };
219  duration().install(duration_getter);
220 
221  std::function<bool()> video_type_getter = [this]()
222  {
223  return d->engine->is_video_source().get();
224  };
225  is_video_source().install(video_type_getter);
226 
227  std::function<bool()> audio_type_getter = [this]()
228  {
229  return d->engine->is_audio_source().get();
230  };
231  is_audio_source().install(audio_type_getter);
232 
233  d->engine->about_to_finish_signal().connect([this]()
234  {
235  if (d->track_list->has_next())
236  {
237  Track::UriType uri = d->track_list->query_uri_for_track(d->track_list->next());
238  if (!uri.empty())
239  d->parent->open_uri(uri);
240  }
241  });
242 
243  d->engine->seeked_to_signal().connect([this](uint64_t value)
244  {
245  seeked_to()(value);
246  });
247 
248  d->engine->end_of_stream_signal().connect([this]()
249  {
250  end_of_stream()();
251  });
252 
253  d->engine->playback_status_changed_signal().connect([this](const Player::PlaybackStatus& status)
254  {
255  playback_status_changed()(status);
256  });
257 }
258 
260 {
261 }
262 
263 std::shared_ptr<media::TrackList> media::PlayerImplementation::track_list()
264 {
265  return d->track_list;
266 }
267 
268 // TODO: Convert this to be a property instead of sync call
270 {
271  return d->key;
272 }
273 
275 {
276  return d->engine->open_resource_for_uri(uri);
277 }
278 
279 void media::PlayerImplementation::create_video_sink(uint32_t texture_id)
280 {
281  d->engine->create_video_sink(texture_id);
282 }
283 
285 {
286  // This method is client-side only and is simply a no-op for the service side
287  return NULL;
288 }
289 
291 {
292 }
293 
295 {
296 }
297 
299 {
300  d->engine->play();
301 }
302 
304 {
305  d->engine->pause();
306 }
307 
309 {
310  d->engine->stop();
311 }
312 
314  UNUSED FrameAvailableCb cb, UNUSED void *context)
315 {
316  // This method is client-side only and is simply a no-op for the service side
317 }
318 
320  UNUSED PlaybackCompleteCb cb, UNUSED void *context)
321 {
322  // This method is client-side only and is simply a no-op for the service side
323 }
324 
325 void media::PlayerImplementation::seek_to(const std::chrono::microseconds& ms)
326 {
327  d->engine->seek_to(ms);
328 }
void * GLConsumerWrapperHybris
Definition: player.h:43
virtual void set_playback_complete_callback(PlaybackCompleteCb cb, void *context)
virtual GLConsumerWrapperHybris gl_consumer() const
virtual const core::Property< PlaybackStatus > & playback_status() const
virtual const core::Property< bool > & is_video_source() const
std::shared_ptr< TrackListImplementation > track_list
virtual const core::Signal< void > & end_of_stream() const
virtual const core::Property< bool > & can_seek() const
virtual const core::Property< bool > & is_shuffle() const
virtual const core::Property< bool > & can_go_next() const
virtual const core::Property< bool > & can_go_previous() const
virtual const core::Property< uint64_t > & duration() const
virtual const core::Property< bool > & can_play() const
#define UNUSED
virtual const core::Signal< uint64_t > & seeked_to() const
PlayerImplementation(const core::dbus::types::ObjectPath &session_path, const std::shared_ptr< Service > &service, PlayerKey key)
virtual const core::Property< bool > & can_pause() const
virtual const core::Property< LoopStatus > & loop_status() const
virtual const core::Property< PlaybackRate > & playback_rate() const
virtual void create_video_sink(uint32_t texture_id)
Private(PlayerImplementation *parent, const dbus::types::ObjectPath &session_path, const std::shared_ptr< media::Service > &service, PlayerImplementation::PlayerKey key)
std::shared_ptr< dbus::Object > powerd_session
virtual bool open_uri(const Track::UriType &uri)
virtual void seek_to(const std::chrono::microseconds &offset)
virtual void set_frame_available_callback(FrameAvailableCb cb, void *context)
std::string UriType
Definition: track.h:40
virtual core::Signal< PlaybackStatus > & playback_status_changed()
PlayerImplementation::PlayerKey key
virtual const core::Property< bool > & is_audio_source() const
virtual std::shared_ptr< TrackList > track_list()
std::shared_ptr< dbus::Object > uscreen_session
virtual const core::Property< uint64_t > & position() const