Music Hub  ..
A session-wide music playback service
track_list_stub.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 "track_list_stub.h"
20 
21 #include <core/media/player.h>
22 #include <core/media/track_list.h>
23 
24 #include "property_stub.h"
25 #include "track_list_traits.h"
26 #include "the_session_bus.h"
27 
28 #include "mpris/player.h"
29 #include "mpris/track_list.h"
30 
32 
33 #include <core/dbus/property.h>
34 #include <core/dbus/types/object_path.h>
35 #include <core/dbus/types/variant.h>
36 #include <core/dbus/types/stl/map.h>
37 #include <core/dbus/types/stl/vector.h>
38 
39 #include <limits>
40 
41 namespace dbus = core::dbus;
42 namespace media = core::ubuntu::media;
43 
45 {
48  const std::shared_ptr<media::Player>& parent,
49  const dbus::Object::Ptr& object)
50  : impl(impl),
51  parent(parent),
52  object(object),
53  can_edit_tracks(object->get_property<mpris::TrackList::Properties::CanEditTracks>()),
54  tracks(object->get_property<mpris::TrackList::Properties::Tracks>()),
55  signals
56  {
57  object->get_signal<mpris::TrackList::Signals::TrackAdded>(),
58  object->get_signal<mpris::TrackList::Signals::TracksAdded>(),
59  object->get_signal<mpris::TrackList::Signals::TrackMoved>(),
60  object->get_signal<mpris::TrackList::Signals::TrackRemoved>(),
61  object->get_signal<mpris::TrackList::Signals::TrackListReset>(),
62  object->get_signal<mpris::TrackList::Signals::TrackListReplaced>(),
63  object->get_signal<mpris::TrackList::Signals::TrackChanged>()
64  }
65  {
66  }
67 
69  std::shared_ptr<media::Player> parent;
70  dbus::Object::Ptr object;
71 
72  std::shared_ptr<core::dbus::Property<mpris::TrackList::Properties::CanEditTracks>> can_edit_tracks;
73  std::shared_ptr<core::dbus::Property<mpris::TrackList::Properties::Tracks>> tracks;
74 
75 
76  struct Signals
77  {
78  typedef core::dbus::Signal<mpris::TrackList::Signals::TrackAdded, mpris::TrackList::Signals::TrackAdded::ArgumentType> DBusTrackAddedSignal;
79  typedef core::dbus::Signal<mpris::TrackList::Signals::TracksAdded, mpris::TrackList::Signals::TracksAdded::ArgumentType> DBusTracksAddedSignal;
80  typedef core::dbus::Signal<mpris::TrackList::Signals::TrackMoved, mpris::TrackList::Signals::TrackMoved::ArgumentType> DBusTrackMovedSignal;
81  typedef core::dbus::Signal<mpris::TrackList::Signals::TrackRemoved, mpris::TrackList::Signals::TrackRemoved::ArgumentType> DBusTrackRemovedSignal;
82  typedef core::dbus::Signal<
83  mpris::TrackList::Signals::TrackListReset,
84  mpris::TrackList::Signals::TrackListReset::ArgumentType>
86  typedef core::dbus::Signal<mpris::TrackList::Signals::TrackListReplaced, mpris::TrackList::Signals::TrackListReplaced::ArgumentType> DBusTrackListReplacedSignal;
87  typedef core::dbus::Signal<mpris::TrackList::Signals::TrackChanged, mpris::TrackList::Signals::TrackChanged::ArgumentType> DBusTrackChangedSignal;
88 
89  Signals(const std::shared_ptr<DBusTrackAddedSignal>& track_added,
90  const std::shared_ptr<DBusTracksAddedSignal>& tracks_added,
91  const std::shared_ptr<DBusTrackMovedSignal>& track_moved,
92  const std::shared_ptr<DBusTrackRemovedSignal>& track_removed,
93  const std::shared_ptr<DBusTrackListResetSignal>& track_list_reset,
94  const std::shared_ptr<DBusTrackListReplacedSignal>& track_list_replaced,
95  const std::shared_ptr<DBusTrackChangedSignal>& track_changed)
96  : on_track_added(),
103  dbus
104  {
105  track_added,
106  tracks_added,
107  track_moved,
108  track_removed,
109  track_list_reset,
110  track_list_replaced,
111  track_changed,
112  }
113  {
114  dbus.on_track_added->connect([this](const Track::Id& id)
115  {
116  MH_DEBUG("OnTrackAdded signal arrived via the bus.");
117  on_track_added(id);
118  });
119 
120  dbus.on_tracks_added->connect([this](const media::TrackList::ContainerURI& tracks)
121  {
122  MH_DEBUG("OnTracksAdded signal arrived via the bus.");
123  on_tracks_added(tracks);
124  });
125 
126  dbus.on_track_moved->connect([this](const media::TrackList::TrackIdTuple& ids)
127  {
128  MH_DEBUG("OnTrackMoved signal arrived via the bus.");
129  on_track_moved(ids);
130  });
131 
132  dbus.on_track_removed->connect([this](const Track::Id& id)
133  {
134  MH_DEBUG("OnTrackRemoved signal arrived via the bus.");
135  on_track_removed(id);
136  });
137 
138  dbus.on_track_list_reset->connect([this](void)
139  {
140  MH_DEBUG("OnTrackListReset signal arrived via the bus.");
142  });
143 
144  dbus.on_track_list_replaced->connect([this](const media::TrackList::ContainerTrackIdTuple& list)
145  {
146  MH_DEBUG("OnTrackListReplaced signal arrived via the bus.");
148  });
149 
150  dbus.on_track_changed->connect([this](const Track::Id& id)
151  {
152  MH_DEBUG("OnTrackChanged signal arrived via the bus.");
153  on_track_changed(id);
154  });
155  }
156 
157  core::Signal<Track::Id> on_track_added;
158  core::Signal<media::TrackList::ContainerURI> on_tracks_added;
159  core::Signal<media::TrackList::TrackIdTuple> on_track_moved;
160  core::Signal<Track::Id> on_track_removed;
161  core::Signal<void> on_track_list_reset;
162  core::Signal<media::TrackList::ContainerTrackIdTuple> on_track_list_replaced;
163  core::Signal<Track::Id> on_track_changed;
164  core::Signal<Track::Id> on_go_to_track;
165  core::Signal<void> on_end_of_tracklist;
166 
167  struct DBus
168  {
169  std::shared_ptr<DBusTrackAddedSignal> on_track_added;
170  std::shared_ptr<DBusTracksAddedSignal> on_tracks_added;
171  std::shared_ptr<DBusTrackMovedSignal> on_track_moved;
172  std::shared_ptr<DBusTrackRemovedSignal> on_track_removed;
173  std::shared_ptr<DBusTrackListResetSignal> on_track_list_reset;
174  std::shared_ptr<DBusTrackListReplacedSignal> on_track_list_replaced;
175  std::shared_ptr<DBusTrackChangedSignal> on_track_changed;
176  } dbus;
177  } signals;
178 };
179 
181  const std::shared_ptr<media::Player>& parent,
182  const core::dbus::Object::Ptr& object)
183  : d(new Private(this, parent, object))
184 {
185 }
186 
188 {
189 }
190 
191 const core::Property<bool>& media::TrackListStub::can_edit_tracks() const
192 {
193  return *d->can_edit_tracks;
194 }
195 
196 const core::Property<media::TrackList::Container>& media::TrackListStub::tracks() const
197 {
198  return *d->tracks;
199 }
200 
202 {
203  auto op = d->object->invoke_method_synchronously<
204  mpris::TrackList::GetTracksMetadata,
205  std::map<std::string, std::string>>(id);
206 
207  if (op.is_error())
208  throw std::runtime_error("Problem querying meta data for track: " + op.error());
209 
210  media::Track::MetaData md;
211  for(auto pair : op.value())
212  {
213  md.set(pair.first, pair.second);
214  }
215  return md;
216 }
217 
219 {
220  auto op = d->object->invoke_method_synchronously<
221  mpris::TrackList::GetTracksUri,
222  std::string>(id);
223 
224  if (op.is_error())
225  throw std::runtime_error("Problem querying track for uri: " + op.error());
226 
227  return op.value();
228 }
229 
231  const media::Track::UriType& uri,
232  const media::Track::Id& position,
233  bool make_current)
234 {
235  auto op = d->object->invoke_method_synchronously<mpris::TrackList::AddTrack, void>(
236  uri,
237  position,
238  make_current);
239 
240  if (op.is_error())
241  {
242  if (op.error().name() ==
244  throw media::TrackList::Errors::InsufficientPermissionsToAddTrack{};
245  else if (op.error().name() == mpris::Player::Error::UriNotFound::name)
246  throw media::Player::Errors::UriNotFound{op.error().print()};
247  else
248  throw std::runtime_error{op.error().print()};
249  }
250 }
251 
253 {
254  auto op = d->object->invoke_method_synchronously<mpris::TrackList::AddTracks, void>(
255  uris,
256  position);
257 
258  if (op.is_error())
259  {
260  if (op.error().name() ==
262  throw media::TrackList::Errors::InsufficientPermissionsToAddTrack{};
263  else if (op.error().name() == mpris::Player::Error::UriNotFound::name)
264  throw media::Player::Errors::UriNotFound{op.error().print()};
265  else
266  throw std::runtime_error{op.error().print()};
267  }
268 }
269 
271 {
272  auto op = d->object->invoke_method_synchronously<mpris::TrackList::MoveTrack, void>(id, to);
273 
274  if (op.is_error())
275  {
276  if (op.error().name() ==
278  throw media::TrackList::Errors::FailedToMoveTrack{};
279  else if (op.error().name() ==
281  throw media::TrackList::Errors::FailedToFindMoveTrackSource{op.error().print()};
282  else if (op.error().name() ==
284  throw media::TrackList::Errors::FailedToFindMoveTrackDest{op.error().print()};
285  else
286  throw std::runtime_error{op.error().print()};
287 
288  return false;
289  }
290 
291  return true;
292 }
293 
295 {
296  auto op = d->object->invoke_method_synchronously<mpris::TrackList::RemoveTrack, void>(
297  track);
298 
299  if (op.is_error())
300  {
301  if (op.error().name() ==
303  throw media::TrackList::Errors::TrackNotFound{};
304  else
305  throw std::runtime_error{"Problem removing track: " + op.error().print()};
306  }
307 }
308 
310 {
311  auto op = d->object->invoke_method_synchronously<mpris::TrackList::GoTo, void>(track);
312 
313  if (op.is_error())
314  throw std::runtime_error("Problem adding track: " + op.error());
315 }
316 
318 {
319  // TODO: Add this to the dbus interface on the server and implement a proper dbus method call
320  return media::Track::Id{"/empty/track/id"};
321 }
322 
324 {
325  // TODO: Add this to the dbus interface on the server and implement a proper dbus method call
326  return media::Track::Id{"/empty/track/id"};
327 }
328 
330 {
331  auto op = d->object->invoke_method_synchronously<mpris::TrackList::Reset, void>();
332 
333  if (op.is_error())
334  throw std::runtime_error("Problem resetting tracklist: " + op.error());
335 }
336 
337 const core::Signal<media::TrackList::ContainerTrackIdTuple>& media::TrackListStub::on_track_list_replaced() const
338 {
339  return d->signals.on_track_list_replaced;
340 }
341 
342 const core::Signal<media::Track::Id>& media::TrackListStub::on_track_added() const
343 {
344  return d->signals.on_track_added;
345 }
346 
347 const core::Signal<media::TrackList::ContainerURI>& media::TrackListStub::on_tracks_added() const
348 {
349  return d->signals.on_tracks_added;
350 }
351 
352 const core::Signal<media::TrackList::TrackIdTuple>& media::TrackListStub::on_track_moved() const
353 {
354  return d->signals.on_track_moved;
355 }
356 
357 const core::Signal<media::Track::Id>& media::TrackListStub::on_track_removed() const
358 {
359  return d->signals.on_track_removed;
360 }
361 
362 const core::Signal<void>& media::TrackListStub::on_track_list_reset() const
363 {
364  return d->signals.on_track_list_reset;
365 }
366 
367 const core::Signal<media::Track::Id>& media::TrackListStub::on_track_changed() const
368 {
369  return d->signals.on_track_changed;
370 }
371 
372 const core::Signal<media::Track::Id>& media::TrackListStub::on_go_to_track() const
373 {
374  return d->signals.on_go_to_track;
375 }
376 
377 const core::Signal<void>& media::TrackListStub::on_end_of_tracklist() const
378 {
379  return d->signals.on_end_of_tracklist;
380 }
core::dbus::Signal< mpris::TrackList::Signals::TrackMoved, mpris::TrackList::Signals::TrackMoved::ArgumentType > DBusTrackMovedSignal
Private(TrackListStub *impl, const std::shared_ptr< media::Player > &parent, const dbus::Object::Ptr &object)
core::dbus::Signal< mpris::TrackList::Signals::TracksAdded, mpris::TrackList::Signals::TracksAdded::ArgumentType > DBusTracksAddedSignal
core::Signal< Track::Id > on_track_changed
const core::Signal< TrackIdTuple > & on_track_moved() const
std::shared_ptr< core::dbus::Property< mpris::TrackList::Properties::CanEditTracks > > can_edit_tracks
std::shared_ptr< DBusTrackMovedSignal > on_track_moved
void go_to(const Track::Id &track)
std::shared_ptr< DBusTrackListResetSignal > on_track_list_reset
std::shared_ptr< DBusTrackListReplacedSignal > on_track_list_replaced
std::shared_ptr< DBusTrackRemovedSignal > on_track_removed
const core::Property< bool > & can_edit_tracks() const
void add_track_with_uri_at(const Track::UriType &uri, const Track::Id &position, bool make_current)
std::shared_ptr< DBusTracksAddedSignal > on_tracks_added
const core::Signal< void > & on_track_list_reset() const
Signals(const std::shared_ptr< DBusTrackAddedSignal > &track_added, const std::shared_ptr< DBusTracksAddedSignal > &tracks_added, const std::shared_ptr< DBusTrackMovedSignal > &track_moved, const std::shared_ptr< DBusTrackRemovedSignal > &track_removed, const std::shared_ptr< DBusTrackListResetSignal > &track_list_reset, const std::shared_ptr< DBusTrackListReplacedSignal > &track_list_replaced, const std::shared_ptr< DBusTrackChangedSignal > &track_changed)
Track::MetaData query_meta_data_for_track(const Track::Id &id)
void remove_track(const Track::Id &id)
core::dbus::Signal< mpris::TrackList::Signals::TrackListReplaced, mpris::TrackList::Signals::TrackListReplaced::ArgumentType > DBusTrackListReplacedSignal
const core::Signal< ContainerTrackIdTuple > & on_track_list_replaced() const
void set(const typename Tag::ValueType &value)
Definition: track.h:68
Track::UriType query_uri_for_track(const Track::Id &id)
core::Signal< media::TrackList::TrackIdTuple > on_track_moved
std::tuple< std::vector< Track::Id >, Track::Id > ContainerTrackIdTuple
Definition: track_list.h:45
#define MH_DEBUG(...)
Definition: logger.h:123
const core::Signal< Track::Id > & on_track_added() const
static constexpr const char * name
Definition: player.h:133
core::dbus::Signal< mpris::TrackList::Signals::TrackListReset, mpris::TrackList::Signals::TrackListReset::ArgumentType > DBusTrackListResetSignal
core::Signal< media::TrackList::ContainerURI > on_tracks_added
std::shared_ptr< media::Player > parent
const core::Signal< Track::Id > & on_track_removed() const
struct media::TrackListStub::Private::Signals signals
const core::Signal< Track::Id > & on_go_to_track() const
std::shared_ptr< DBusTrackChangedSignal > on_track_changed
void add_tracks_with_uri_at(const ContainerURI &uris, const Track::Id &position)
TrackListStub(const std::shared_ptr< Player > &parent, const core::dbus::Object::Ptr &object)
const core::Signal< ContainerURI > & on_tracks_added() const
struct media::TrackListStub::Private::Signals::DBus dbus
const core::Signal< void > & on_end_of_tracklist() const
static constexpr const char * name
Definition: track_list.h:64
core::dbus::Signal< mpris::TrackList::Signals::TrackRemoved, mpris::TrackList::Signals::TrackRemoved::ArgumentType > DBusTrackRemovedSignal
const core::Signal< Track::Id > & on_track_changed() const
std::tuple< Track::Id, Track::Id > TrackIdTuple
Definition: track_list.h:46
bool move_track(const Track::Id &id, const Track::Id &to)
std::shared_ptr< core::dbus::Property< mpris::TrackList::Properties::Tracks > > tracks
std::string UriType
Definition: track.h:40
const core::Property< Container > & tracks() const
core::Signal< Track::Id > on_track_added
core::dbus::Signal< mpris::TrackList::Signals::TrackChanged, mpris::TrackList::Signals::TrackChanged::ArgumentType > DBusTrackChangedSignal
core::Signal< Track::Id > on_track_removed
core::Signal< media::TrackList::ContainerTrackIdTuple > on_track_list_replaced
std::vector< Track::UriType > ContainerURI
Definition: track_list.h:44
core::dbus::Signal< mpris::TrackList::Signals::TrackAdded, mpris::TrackList::Signals::TrackAdded::ArgumentType > DBusTrackAddedSignal
static constexpr const char * name
Definition: track_list.h:88
std::shared_ptr< DBusTrackAddedSignal > on_track_added
core::Signal< Track::Id > on_go_to_track