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 "gstreamer/engine.h"
27 
28 #define UNUSED __attribute__((unused))
29 
30 namespace media = core::ubuntu::media;
31 namespace dbus = core::dbus;
32 
33 using namespace std;
34 
36 {
37  Private(PlayerImplementation* parent,
38  const dbus::types::ObjectPath& session_path,
39  const std::shared_ptr<media::Service>& service,
40  PlayerImplementation::PlayerKey key)
41  : parent(parent),
42  service(service),
43  engine(std::make_shared<gstreamer::Engine>()),
44  session_path(session_path),
45  track_list(
46  new media::TrackListImplementation(
47  session_path.as_string() + "/TrackList",
48  engine->meta_data_extractor())),
49  disp_lock_name("media-hub-video-playback"),
50  sys_lock_name("media-hub-music-playback"),
51  key(key)
52  {
53  auto bus = std::shared_ptr<dbus::Bus>(new dbus::Bus(core::dbus::WellKnownBus::system));
54  bus->install_executor(dbus::asio::make_executor(bus));
55 
56  auto stub_service = dbus::Service::use_service(bus, dbus::traits::Service<core::Powerd>::interface_name());
57  powerd_session = stub_service->object_for_path(dbus::types::ObjectPath("/com/canonical/powerd"));
58 
59  engine->state().changed().connect(
60  [parent, this](const Engine::State& state)
61  {
62  switch(state)
63  {
64  case Engine::State::ready:
65  {
66  parent->playback_status().set(media::Player::ready);
67  clear_power_state();
68  break;
69  }
70  case Engine::State::playing:
71  {
72  parent->playback_status().set(media::Player::playing);
73  request_power_state();
74  break;
75  }
76  case Engine::State::stopped:
77  {
78  parent->playback_status().set(media::Player::stopped);
79  clear_power_state();
80  break;
81  }
82  case Engine::State::paused:
83  {
84  parent->playback_status().set(media::Player::paused);
85  clear_power_state();
86  break;
87  }
88  default:
89  break;
90  };
91  });
92 
93  }
94 
96  {
97  if (parent->is_video_source())
98  {
99  if (disp_cookie.empty())
100  {
101  auto result = powerd_session->invoke_method_synchronously<core::Powerd::requestDisplayState, std::string>(disp_lock_name, static_cast<int>(1), static_cast<unsigned int>(4));
102  if (result.is_error())
103  throw std::runtime_error(result.error().print());
104 
105  disp_cookie = result.value();
106  }
107  }
108  else
109  {
110  if (sys_cookie.empty())
111  {
112  auto result = powerd_session->invoke_method_synchronously<core::Powerd::requestSysState, std::string>(sys_lock_name, static_cast<int>(1));
113  if (result.is_error())
114  throw std::runtime_error(result.error().print());
115 
116  sys_cookie = result.value();
117  }
118  }
119  }
120 
122  {
123  if (parent->is_video_source())
124  {
125  if (!disp_cookie.empty())
126  {
127  powerd_session->invoke_method_synchronously<core::Powerd::clearDisplayState, void>(disp_cookie);
128  disp_cookie.clear();
129  }
130  }
131  else
132  {
133  if (!sys_cookie.empty())
134  {
135  powerd_session->invoke_method_synchronously<core::Powerd::clearSysState, void>(sys_cookie);
136  sys_cookie.clear();
137  }
138  }
139  }
140 
141  PlayerImplementation* parent;
142  std::shared_ptr<Service> service;
143  std::shared_ptr<Engine> engine;
144  dbus::types::ObjectPath session_path;
145  std::shared_ptr<TrackListImplementation> track_list;
146  std::shared_ptr<dbus::Object> powerd_session;
147  std::string disp_lock_name;
148  std::string sys_lock_name;
149  std::string disp_cookie;
150  std::string sys_cookie;
151  PlayerImplementation::PlayerKey key;
152 };
153 
155  const dbus::types::ObjectPath& session_path,
156  const std::shared_ptr<Service>& service,
157  PlayerKey key)
158  : media::PlayerSkeleton(session_path),
159  d(new Private(
160  this,
161  session_path,
162  service,
163  key))
164 {
165  // Initializing default values for properties
166  can_play().set(true);
167  can_pause().set(true);
168  can_seek().set(true);
169  can_go_previous().set(true);
170  can_go_next().set(true);
171  is_video_source().set(false);
172  is_audio_source().set(false);
173  is_shuffle().set(true);
174  playback_rate().set(1.f);
175  playback_status().set(Player::PlaybackStatus::null);
176  loop_status().set(Player::LoopStatus::none);
177  position().set(0);
178  duration().set(0);
179 
180  // Make sure that the Position property gets updated from the Engine
181  // every time the client requests position
182  std::function<uint64_t()> position_getter = [this]()
183  {
184  return d->engine->position().get();
185  };
186  position().install(position_getter);
187 
188  // Make sure that the Duration property gets updated from the Engine
189  // every time the client requests duration
190  std::function<uint64_t()> duration_getter = [this]()
191  {
192  return d->engine->duration().get();
193  };
194  duration().install(duration_getter);
195 
196  std::function<bool()> video_type_getter = [this]()
197  {
198  return d->engine->is_video_source().get();
199  };
200  is_video_source().install(video_type_getter);
201 
202  std::function<bool()> audio_type_getter = [this]()
203  {
204  return d->engine->is_audio_source().get();
205  };
206  is_audio_source().install(audio_type_getter);
207 
208  d->engine->about_to_finish_signal().connect([this]()
209  {
210  if (d->track_list->has_next())
211  {
212  Track::UriType uri = d->track_list->query_uri_for_track(d->track_list->next());
213  if (!uri.empty())
214  d->parent->open_uri(uri);
215  }
216  });
217 
218  d->engine->seeked_to_signal().connect([this](uint64_t value)
219  {
220  seeked_to()(value);
221  });
222 
223  d->engine->end_of_stream_signal().connect([this]()
224  {
225  end_of_stream()();
226  });
227 
228  d->engine->playback_status_changed_signal().connect([this](const Player::PlaybackStatus& status)
229  {
230  playback_status_changed()(status);
231  });
232 }
233 
235 {
236 }
237 
238 std::shared_ptr<media::TrackList> media::PlayerImplementation::track_list()
239 {
240  return d->track_list;
241 }
242 
243 // TODO: Convert this to be a property instead of sync call
245 {
246  return d->key;
247 }
248 
250 {
251  return d->engine->open_resource_for_uri(uri);
252 }
253 
254 void media::PlayerImplementation::create_video_sink(uint32_t texture_id)
255 {
256  d->engine->create_video_sink(texture_id);
257 }
258 
260 {
261  // This method is client-side only and is simply a no-op for the service side
262  return NULL;
263 }
264 
266 {
267 }
268 
270 {
271 }
272 
274 {
275  d->engine->play();
276 }
277 
279 {
280  d->engine->pause();
281 }
282 
284 {
285  d->engine->stop();
286 }
287 
289  UNUSED FrameAvailableCb cb, UNUSED void *context)
290 {
291  // This method is client-side only and is simply a no-op for the service side
292 }
293 
295  UNUSED PlaybackCompleteCb cb, UNUSED void *context)
296 {
297  // This method is client-side only and is simply a no-op for the service side
298 }
299 
300 void media::PlayerImplementation::seek_to(const std::chrono::microseconds& ms)
301 {
302  d->engine->seek_to(ms);
303 }
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()
virtual const core::Property< uint64_t > & position() const