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